/*
 * Copyright (c) 2011 by RibbonSoft, GmbH. All rights reserved.
 * 
 * This file is part of the QCAD project.
 *
 * Licensees holding valid QCAD Professional Edition licenses 
 * may use this file in accordance with the QCAD License
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, 
 * INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE.
 * 
 * See http://www.ribbonsoft.com for further details.
 */

include("scripts/Navigation/DefaultNavigation/DefaultNavigation.js");
include("scripts/File/File.js");

function CompareNavigation(mdiChild, viewName) {
    DefaultNavigation.call(this, mdiChild);
    this.viewName = viewName;
}

CompareNavigation.prototype = new DefaultNavigation();


CompareNavigation.prototype.mouseMoveEvent = function(event) {
    DefaultNavigation.prototype.mouseMoveEvent.call(this, event);
    Compare.synchronizeViews(this.viewName);
};

CompareNavigation.prototype.wheelEvent = function(event) {
    DefaultNavigation.prototype.wheelEvent.call(this, event);
    Compare.synchronizeViews(this.viewName);
};


function Compare(guiAction) {
    File.call(this, guiAction);
}

Compare.prototype = new File();

Compare.prototype.beginEvent = function(isOpen) {
    File.prototype.beginEvent.call(this);
 
    Compare.reset();
    Compare.createDialog();
};

Compare.reset = function() {
    var settings = RSettings.getQSettings();
    Compare.setDistanceTolerance(
        settings.value("Compare/DistanceTolerance", 1.0e-5));
    Compare.setAngleTolerance(
        settings.value("Compare/AngleTolerance", 1.0e-5));
    Compare.doc1 = undefined;
    Compare.doc2 = undefined;
    Compare.di1 = undefined;
    Compare.di2 = undefined;
    Compare.view1 = undefined;
    Compare.view2 = undefined;
    Compare.skipUpdate = false;
};

Compare.importFiles = function(file1, file2) {
    var widgets = getWidgets(Compare.formWidget);
    
    if(file1 != undefined && file1 != ""){
        var storage1 = new RMemoryStorage();
        var spatialIndex1 = new RSpatialIndexNavel();
        Compare.doc1 = new RDocument(storage1, spatialIndex1);
        Compare.di1 = new RDocumentInterface(Compare.doc1);
        Compare.di1.importFile(file1);
        if(widgets != undefined){
            widgets["FilePath1"].text = file1;
        }
    }

    if(file2 != undefined && file2 != ""){
        var storage2 = new RMemoryStorage();
        var spatialIndex2 = new RSpatialIndexNavel();
        Compare.doc2 = new RDocument(storage2, spatialIndex2);
        Compare.di2 = new RDocumentInterface(Compare.doc2);
        Compare.di2.importFile(file2);
        if(widgets != undefined){
            widgets["FilePath2"].text = file2;
        }
    }
};

Compare.isReadyToCompare = function() {
    if(Compare.di1 != undefined && Compare.di2 != undefined){
        return true;
    }
    return false;
};

Compare.diff = function() {
    if(!Compare.isReadyToCompare()){
        return;
    }
    
    QApplication.setOverrideCursor(new QCursor( Qt.WaitCursor));

    var newIds = new Array();
    var missingIds = new Array();
    Compare.diffEntities(newIds, missingIds);
    Compare.diffLayers(newIds, missingIds);
    
    QApplication.restoreOverrideCursor();

    if(newIds.length > 0){
        qDebug("Compare.js:", "diff(): newIds:", newIds);
        qDebug("Compare.js:", "diff(): missingIds:", missingIds);
        //qDebug("Compare.js:", "diff(): doc1 dump:");
        //Compare.doc1.dump();
        //qDebug("Compare.js:", "diff(): doc2 dump:");
        //Compare.doc2.dump();
    }
    
    return [ newIds, missingIds ];
};

Compare.diffLayers = function(newIds, missingIds) {
    var i, j, id1, id2, layer1, layer2, found;

    var layerIds1 = Compare.doc1.queryAllLayers();
    var layerIds2 = Compare.doc2.queryAllLayers();

    for (i = 0; i < layerIds1.length; ++i) {
        id1 = layerIds1[i];
        layer1 = Compare.doc1.queryLayer(id1);
        found = false;
        for (j = 0; j < layerIds2.length; ++j) {
            id2 = layerIds2[j];
            layer2 = Compare.doc2.queryLayer(id2);
            if (Compare.compareLayer(layer1, layer2)) {
                found = true;
                break;
            }
        }
        if (!found) {
            newIds.push(id1);
        }
    }

    for (j = 0; j < layerIds2.length; ++j) {
        id2 = layerIds2[j];
        layer2 = Compare.doc2.queryLayer(id2);
        found = false;
        for (i = 0; i < layerIds1.length; ++i) {
            id1 = layerIds1[i];
            layer1 = Compare.doc1.queryLayer(id1);
            if (Compare.compareLayer(layer1, layer2)) {
                found = true;
                break;
            }
        }
        if (!found) {
            missingIds.push(id2);
        }
    }
};

Compare.diffEntities = function(newIds, missingIds) {
    var i, j, id1, id2, entity1, entity2, found;

    var entityIds1 = Compare.doc1.queryAllEntities();
    var entityIds2 = Compare.doc2.queryAllEntities();

    for (i = 0; i < entityIds1.length; ++i) {
        id1 = entityIds1[i];
        entity1 = Compare.doc1.queryEntity(id1);
        found = false;
        for (j = 0; j < entityIds2.length; ++j) {
            id2 = entityIds2[j];
            entity2 = Compare.doc2.queryEntity(id2);
            if (Compare.compareEntity(entity1, entity2)) {
                found = true;
                break;
            }
        }
        if (!found) {
            newIds.push(id1);
        }
    }

    for (j = 0; j < entityIds2.length; ++j) {
        id2 = entityIds2[j];
        entity2 = Compare.doc2.queryEntity(id2);
        found = false;
        for (i = 0; i < entityIds1.length; ++i) {
            id1 = entityIds1[i];
            entity1 = Compare.doc1.queryEntity(id1);
            if (Compare.compareEntity(entity1, entity2)) {
                found = true;
                break;
            }
        }
        if (!found) {
            missingIds.push(id2);
        }
    }
};

Compare.createDialog = function() {
    var file;
    
    Compare.formWidget = WidgetFactory.createWidget(
            "scripts/Pro/File/Compare", "CompareDialog.ui");
    var widgets = getWidgets(Compare.formWidget);

    widgets["OpenDrawings1"].addItem(qsTr("Please choose"));
    widgets["OpenDrawings2"].addItem(qsTr("Please choose"));
    var files = Compare.getOpenedFiles();
    for (var i=0; i<files.length; ++i) {
        file = files[i];
        var fileName = Compare.getElidedFileName(file);
        widgets["OpenDrawings1"].addItem(fileName, file);
        widgets["OpenDrawings2"].addItem(fileName, file);
    }
    
    var openDrawingsCombo1 = widgets["OpenDrawings1"];
    openDrawingsCombo1["currentIndexChanged(int)"].connect(Compare, function(index) {
        file = openDrawingsCombo1.itemData(index);
        Compare.importFiles(file, undefined);
        Compare.refresh();
    });

    var openDrawingsCombo2 = widgets["OpenDrawings2"];
    openDrawingsCombo2["currentIndexChanged(int)"].connect(Compare, function(index) {
        file = openDrawingsCombo2.itemData(index);
        Compare.importFiles(undefined, file);
        Compare.refresh();
    });

    widgets["Open1"].clicked.connect(Compare, function(){
        var dirPath = widgets["FilePath1"].text;
        file = Compare.openFileDialog(dirPath);
        if(file == undefined){
            return;
        }
        Compare.importFiles(file, undefined);
        Compare.refresh();
    });
    
    widgets["Open2"].clicked.connect(Compare, function(){
        var dirPath = widgets["FilePath2"].text;
        file = Compare.openFileDialog(dirPath);
        if(file == undefined){
            return;
        }
        Compare.importFiles(undefined, file);
        Compare.refresh();
    });
    
    widgets["ShowNewEntities1"].toggled.connect(Compare, function(){
        Compare.update(false);
    });
    widgets["ShowMissingEntities1"].toggled.connect(Compare, function(){
        Compare.update(false);
    });
    widgets["ShowNewEntities2"].toggled.connect(Compare, function(){
        Compare.update(false);
    });
    widgets["ShowMissingEntities2"].toggled.connect(Compare, function(){
        Compare.update(false);
    });

    widgets["Preserve"].clicked.connect(Compare, function(){
        Compare.skipUpdate = true;
        widgets["ShowNewEntities1"].checked = false;
        widgets["ShowMissingEntities1"].checked = false;
        widgets["ShowNewEntities2"].checked = false;
        widgets["ShowMissingEntities2"].checked = false;
        Compare.skipUpdate = false;
        Compare.update();
    });
    
    widgets["Compare"].clicked.connect(Compare, function(){
        Compare.skipUpdate = true;
        widgets["ShowNewEntities1"].checked = true;
        widgets["ShowMissingEntities1"].checked = true;
        widgets["ShowNewEntities2"].checked = true;
        widgets["ShowMissingEntities2"].checked = true;
        Compare.skipUpdate = false;
        Compare.update();
    });
    
    var distTolCombo = widgets["DistanceTolerance"];
    distTolCombo["currentIndexChanged(int)"].connect(Compare, function(index) {
        var distTol = distTolCombo.itemText(index);
        var settings = RSettings.getQSettings();
        settings.setValue("Compare/DistanceTolerance", distTol);
    });    
    distTolCombo.editTextChanged.connect(Compare, function(text) {
        var settings = RSettings.getQSettings();
        settings.setValue("Compare/DistanceTolerance", text);
    });
    Compare.updateDistanceTolCombo();

    var angleTolCombo = widgets["AngleTolerance"];
    angleTolCombo["currentIndexChanged(int)"].connect(Compare, function(index) {
        var angleTol = angleTolCombo.itemText(index);
        var settings = RSettings.getQSettings();
        settings.setValue("Compare/AngleTolerance", angleTol);
    });
    angleTolCombo.editTextChanged.connect(Compare, function(text) {
        var settings = RSettings.getQSettings();
        settings.setValue("Compare/AngleTolerance", text);
    });
    Compare.updateAngleTolCombo();

    Compare.formWidget.show();
};

Compare.updateDistanceTolCombo = function(){
    if(Compare.formWidget == undefined){
        return;
    }
    
    var widgets = getWidgets(Compare.formWidget);
    var distTolCombo = widgets["DistanceTolerance"];
    var i = distTolCombo.findText(Compare.getDistanceTolerance());
    if (i != -1) {
        distTolCombo.currentIndex = i;
    } else {
        distTolCombo.insertItem(0, Compare.getDistanceTolerance());
        distTolCombo.currentIndex = 0;
    }
};

Compare.updateAngleTolCombo = function(){
    if(Compare.formWidget == undefined){
        return;
    }
    
    var widgets = getWidgets(Compare.formWidget);
    var angleTolCombo = widgets["AngleTolerance"];
    var i = angleTolCombo.findText(Compare.getAngleTolerance());
    if (i != -1) {
        angleTolCombo.currentIndex = i;
    } else {
        angleTolCombo.insertItem(0, Compare.getAngleTolerance());
        angleTolCombo.currentIndex = 0;
    }
};

Compare.update = function(doZoom) {
    if (Compare.skipUpdate) {
        return;
    }
    var widgets = getWidgets(Compare.formWidget);
    var file1 = widgets["FilePath1"].text;
    var file2 = widgets["FilePath2"].text;
    Compare.reset();
    Compare.importFiles(file1, file2);
    var ret = Compare.diff(file1, file2);
    Compare.markDifferences(ret);
    Compare.refresh(doZoom);
};

Compare.getElidedFileName = function(fileName) {
    var fi = new QFileInfo(fileName);
    return fi.fileName().elidedText(Compare.formWidget.font, 300) + " ["
        + fi.path().elidedText(Compare.formWidget.font, 250) + "]";
};

Compare.getOpenedFiles = function() {
    var files = new Array();
    var mdiArea = EAction.getMdiArea();
    var windows = mdiArea.subWindowList();
    for ( var i = 0; i < windows.length; ++i) {
        var child = windows[i];
        if(child.getDocument() == undefined){
            // skip for new, not saved files
            continue;
        }
        var file = child.getDocument().getFileName();
        files.push(file);
    }
    return files;
};

Compare.openFileDialog = function(dirPath) {
    if (dirPath == undefined
            || (dirPath != undefined && dirPath == "")) {
        dirPath = QDesktopServices.storageLocation(
                QDesktopServices.DocumentsLocation);
    }
    var fileDlg = new QFileDialog(this, qsTr("Open Drawing"), dirPath, "");
    var filters = RFileImporterRegistry.getFilterStrings();
    var allFilter = filters[0];
    filters = new Array(qsTr("All Files") + " (*)").concat(filters);
    fileDlg.setNameFilters(filters);
    fileDlg.selectNameFilter(allFilter);
    fileDlg.setOption(QFileDialog.DontUseNativeDialog, false);
    fileDlg.fileMode = QFileDialog.ExistingFile;
    if (!fileDlg.exec()) {
        fileDlg.destroy();
        return undefined;
    }
    var file = fileDlg.selectedFiles()[0];
    return file;
};

Compare.markDifferences = function(newAndMissingIds) {
    var i, id, entity, op, storage, trans, ids;

    if (!Compare.isReadyToCompare()) {
        return;
    }

    var widgets = getWidgets(Compare.formWidget);
    var newIds = newAndMissingIds[0];
    var missingIds = newAndMissingIds[1];

    // point of view "document 1"
    if (widgets["ShowNewEntities1"].checked) {
        for (i = 0; i < newIds.length; ++i) {
            id = newIds[i];
            entity = Compare.doc1.queryEntity(id);
            if (isNull(entity)) {
                // not an entity
                continue;
            }
            entity.setColor(new RColor("green"));
            op = new RModifyObjectOperation(entity.data());
            Compare.di1.applyOperation(op);
        }
        widgets["NewEntities1"].text = newIds.length;
    } else {
        widgets["NewEntities1"].text = "";
    }

    if (widgets["ShowMissingEntities1"].checked) {
        for (i = 0; i < missingIds.length; ++i) {
            id = missingIds[i];
            // get entity from doc2
            entity = Compare.doc2.queryEntity(id);
            if (isNull(entity)) {
                // not an entity
                continue;
            }
            entity.setDocument(Compare.doc1);
            // invalidate entity ID
            storage = Compare.di1.getStorage();
            storage.setObjectId(entity.data(), RObject.INVALID_ID);
            // add entity to doc1
            op = new RAddObjectOperation(entity.data());
            trans = Compare.di1.applyOperation(op);
            ids = trans.getAffectedObjects();

            // set entity color to red
            entity = Compare.doc1.queryEntity(ids[0]);
            if (!isNull(entity)) {
                entity.setColor(new RColor("red"));
                op = new RModifyObjectOperation(entity.data());
                Compare.di1.applyOperation(op);
            }
        }
        widgets["MissingEntities1"].text = missingIds.length;
    } else {
        widgets["MissingEntities1"].text = "";
    }

    // point of view "document 2"
    if (widgets["ShowNewEntities2"].checked) {
        for (i = 0; i < missingIds.length; ++i) {
            id = missingIds[i];
            entity = Compare.doc2.queryEntity(id);
            if (isNull(entity)) {
                // not an entity
                continue;
            }
            entity.setColor(new RColor("green"));
            op = new RModifyObjectOperation(entity.data());
            Compare.di2.applyOperation(op);
        }
        widgets["NewEntities2"].text = missingIds.length;
    } else {
        widgets["NewEntities2"].text = "";
    }

    if (widgets["ShowMissingEntities2"].checked) {
        for (i = 0; i < newIds.length; ++i) {
            id = newIds[i];
            // get entity from doc1
            entity = Compare.doc1.queryEntity(id);
            if (isNull(entity)) {
                // not an entity
                continue;
            }
            entity.setDocument(Compare.doc2);
            // invalidate entity ID
            storage = Compare.di2.getStorage();
            storage.setObjectId(entity.data(), RObject.INVALID_ID);
            // add entity to doc2
            op = new RAddObjectOperation(entity.data());
            trans = Compare.di2.applyOperation(op);
            ids = trans.getAffectedObjects();

            // set entity color to red
            entity = Compare.doc2.queryEntity(ids[0]);
            if (!isNull(entity)) {
                entity.setColor(new RColor("red"));
                op = new RModifyObjectOperation(entity.data());
                Compare.di2.applyOperation(op);
            }
        }
        widgets["MissingEntities2"].text = newIds.length;
    } else {
        widgets["MissingEntities2"].text = "";
    }

    if (newIds.length == 0 && missingIds.length == 0) {
        widgets["Info"].text = qsTr("Drawings are identical.");
    } else {
        var txt = qsTr("Drawings are not identical:");
        var entitiesDiffer = false;
        var layersDiffer = false;
        for (i = 0; i < newIds.length; ++i) {
            id = newIds[i];
            obj = Compare.doc1.queryEntity(id);
            if (!isNull(obj)) {
                entitiesDiffer = true;
            }
            obj = Compare.doc1.queryLayer(id);
            if (!isNull(obj)) {
                layersDiffer = true;
            }
        }
        for (i = 0; i < missingIds.length; ++i) {
            id = missingIds[i];
            obj = Compare.doc2.queryEntity(id);
            if (!isNull(obj)) {
                entitiesDiffer = true;
            }
            obj = Compare.doc2.queryLayer(id);
            if (!isNull(obj)) {
                layersDiffer = true;
            }
        }
        if (entitiesDiffer) {
            txt += "<br>- " + qsTr("found different entities");
        }
        if (layersDiffer) {
            txt += "<br>- " + qsTr("found different layers");
        }
        widgets["Info"].text = txt;
    }
};

Compare.refresh = function(doZoom) {
    var navigationAction;

    if (doZoom == undefined) {
        doZoom = true;
    }

    var widgets = getWidgets(Compare.formWidget);

    if (Compare.di1 != undefined) {
        Compare.view1 = widgets["GraphicsView1"];
        Compare.view1.setMargin(10);
        Compare.view1.resize(500, 500);
        var scene1 = new RGraphicsSceneQt(Compare.di1);
        Compare.view1.setScene(scene1);
        Compare.di1.regenerateScenes();
        if (doZoom) {
            Compare.di1.autoZoom();
        }
        navigationAction = new CompareNavigation(EAction.getMdiChild(), "view1");
        Compare.view1.setNavigationAction(navigationAction);
    }

    if (Compare.di2 != undefined) {
        Compare.view2 = widgets["GraphicsView2"];
        Compare.view2.setMargin(10);
        Compare.view2.resize(500, 500);
        var scene2 = new RGraphicsSceneQt(Compare.di2);
        Compare.view2.setScene(scene2);
        Compare.di2.regenerateScenes();
        if (doZoom) {
            Compare.di2.autoZoom();
        }
        navigationAction = new CompareNavigation(EAction.getMdiChild(), "view2");
        Compare.view2.setNavigationAction(navigationAction);
    }

    if (doZoom) {
        if (Compare.di1 != undefined && Compare.di2 != undefined) {
            var box1 = Compare.view1.getRGraphicsView().getBox();
            var box2 = Compare.view2.getRGraphicsView().getBox();
            var xmin = Math.min(box1.getMinimum().x, box2.getMinimum().x);
            var xmax = Math.max(box1.getMaximum().x, box2.getMaximum().x);
            var ymin = Math.min(box1.getMinimum().y, box2.getMinimum().y);
            var ymax = Math.max(box1.getMaximum().y, box2.getMaximum().y);
            var box = new RBox(new RVector(xmin, ymin), new RVector(xmax, ymax));
            Compare.view1.getRGraphicsView().zoomTo(box);
            Compare.view2.getRGraphicsView().zoomTo(box);
        }
    }
};

Compare.synchronizeViews = function(viewName) {
    if (viewName == "view1" && Compare.view2 != undefined) {
        Compare.view2.getRGraphicsView().zoomTo(
                Compare.view1.getRGraphicsView().getBox());
    }
    if (viewName == "view2" && Compare.view1 != undefined) {
        Compare.view1.getRGraphicsView().zoomTo(
                Compare.view2.getRGraphicsView().getBox());
    }
};

Compare.compareLayer = function(layer1, layer2) {
    if(layer1.getName() != layer2.getName()){
        return false;
    }
    // equals() doesn't work here
    // if(layer1.getColor().equals(layer2.getColor())){
    if(!Compare.compareColor(layer1.getColor(), layer2.getColor())){
        return false;
    }
    if(layer1.getLineweight() != layer2.getLineweight()){
        return false;
    }
    return true;
};

Compare.compareEntity = function(entity1, entity2) {
    // always return false for different types
    if (entity1.getType() != entity2.getType()) {
        return false;
    }

    if (isNull(entity1)) {
        return false;
    }
    if (isNull(entity2)) {
        return false;
    }
    
    if (isLineEntity(entity1) && isLineEntity(entity2)) {
        return Compare.compareLine(entity1, entity2);
    }
    if (isPointEntity(entity1) && isPointEntity(entity2)) {
        return Compare.comparePoint(entity1, entity2);
    }
    if (isArcEntity(entity1) && isArcEntity(entity2)) {
        return Compare.compareArc(entity1, entity2);
    }
    if (isCircleEntity(entity1) && isCircleEntity(entity2)) {
        return Compare.compareCircle(entity1, entity2);
    }
    if (isEllipseEntity(entity1) && isEllipseEntity(entity2)) {
        return Compare.compareEllipse(entity1, entity2);
    }
    if (isSolidEntity(entity1) && isSolidEntity(entity2)) {
        return Compare.compareSolid(entity1, entity2);
    }
    if (isSplineEntity(entity1) && isSplineEntity(entity2)) {
        return Compare.compareSpline(entity1, entity2);
    }
    if (isPolylineEntity(entity1) && isPolylineEntity(entity2)) {
        return Compare.comparePolyline(entity1, entity2);
    }
    if (isTextEntity(entity1) && isTextEntity(entity2)) {
        return Compare.compareText(entity1, entity2);
    }
    if (isDimAlignedEntity(entity1) && isDimAlignedEntity(entity2)) {
        return Compare.compareAlignedDimension(entity1, entity2);
    }
    if (isDimDiametricEntity(entity1) && isDimDiametricEntity(entity2)) {
        return Compare.compareDiametricDimension(entity1, entity2);
    }
    if (isDimRotatedEntity(entity1) && isDimRotatedEntity(entity2)) {
        return Compare.compareRotatedDimension(entity1, entity2);
    }
    if (isDimOrdinateEntity(entity1) && isDimOrdinateEntity(entity2)) {
        return Compare.compareOrdinateDimension(entity1, entity2);
    }
    if (isDimRadialEntity(entity1) && isDimRadialEntity(entity2)) {
        return Compare.compareRadialDimension(entity1, entity2);
    }
    if (isDimAngularEntity(entity1) && isDimAngularEntity(entity2)) {
        return Compare.compareAngularDimension(entity1, entity2);
    }
    if (isLeaderEntity(entity1) && isLeaderEntity(entity2)) {
        return Compare.compareLeaderEntity(entity1, entity2);
    }
    if(isImageEntity(entity1) && isImageEntity(entity2)){
        return Compare.compareImage(entity1, entity2);
    }
    if(isHatchEntity(entity1) && isHatchEntity(entity2)){
        return Compare.compareHatch(entity1, entity2);
    }
    if (isBlockReferenceEntity(entity1) && isBlockReferenceEntity(entity2)) {
        return Compare.compareBlockRef(entity1, entity2);
    }

    qWarning("Compare.js:", "compareEntity(): cannot compare unknown type:", entity1);
    qDebug("isSolidEntity(entity1): ", isSolidEntity(entity1));
    qDebug("isSolidEntity(entity2): ", isSolidEntity(entity2));
    qDebug("isOfType(entity1, RSolidEntityPointer): ", isOfType(entity1, RSolidEntityPointer));
    qDebug("isOfType(entity2, RSolidEntityPointer): ", isOfType(entity2, RSolidEntityPointer));
    return false;
};

Compare.compareShape = function(shape1, shape2) {
    if (isLineShape(shape1) && isLineShape(shape2)) {
        return Compare.compareLine(shape1, shape2);
    }
    if (isPointShape(shape1) && isPointShape(shape2)) {
        return Compare.comparePoint(shape1, shape2);
    }
    if (isArcShape(shape1) && isArcShape(shape2)) {
        return Compare.compareArc(shape1, shape2);
    }
    if (isCircleShape(shape1) && isCircleShape(shape2)) {
        return Compare.compareCircle(shape1, shape2);
    }
    if (isEllipseShape(shape1) && isEllipseShape(shape2)) {
        return Compare.compareEllipse(shape1, shape2);
    }
    if (isSplineShape(shape1) && isSplineShape(shape2)) {
        return Compare.compareSpline(shape1, shape2);
    }
    if (isPolylineShape(shape1) && isPolylineShape(shape2)) {
        return Compare.comparePolyline(shape1, shape2);
    }

    return false;
};

Compare.compareLine = function(line1, line2) {
    var tol = Compare.getDistanceTolerance();
    var sp1 = line1.getStartPoint();
    var sp2 = line2.getStartPoint();
    var ep1 = line1.getEndPoint();
    var ep2 = line2.getEndPoint();

    if (sp1.getDistanceTo(sp2) <= tol && ep1.getDistanceTo(ep2) <= tol){
        return true;
    }

    if (sp1.getDistanceTo(ep2) <= tol && ep1.getDistanceTo(sp2) <= tol){
        return true;
    }
    
    return false;
};

Compare.compareDimension = function(dim1, dim2) {
    if(dim1.getText() !== dim2.getText()){
        return false;
    }
    
    var tol = Compare.getDistanceTolerance();
    
    var dp1 = dim1.getDefinitionPoint();
    var dp2 = dim2.getDefinitionPoint();
    if (dp1.getDistanceTo(dp2) > tol) {
        return false;
    }
    
    var tp1 = dim1.getTextPosition();
    var tp2 = dim2.getTextPosition();
    if (tp1.getDistanceTo(tp2) > tol) {
        return false;
    }
    
    return true;
};

Compare.compareAngularDimension = function(dim1, dim2) {
    var tol;
    
    if(! Compare.compareDimension(dim1, dim2)){
        return false;
    }

    tol = Compare.getDistanceTolerance();
    
    var data1 = dim1.getData();
    var data2 = dim2.getData();
    
    var el1s1 = data1.getExtensionLine1Start();
    var el1s2 = data2.getExtensionLine1Start();
    if (el1s1.getDistanceTo(el1s2) > tol) {
        return false;
    }

    var el1e1 = data1.getExtensionLine1End();
    var el1e2 = data2.getExtensionLine1End();
    if (el1e1.getDistanceTo(el1e2) > tol) {
        return false;
    }

    var el2s1 = data1.getExtensionLine2Start();
    var el2s2 = data2.getExtensionLine2Start();
    if (el2s1.getDistanceTo(el2s2) > tol) {
        return false;
    }

    var el2e1 = data1.getExtensionLine2End();
    var el2e2 = data2.getExtensionLine2End();
    if (el2e1.getDistanceTo(el2e2) > tol) {
        return false;
    }

    var dap1 = data1.getDimArcPosition();
    var dap2 = data2.getDimArcPosition();
    if (dap1.getDistanceTo(dap2) > tol) {
        return false;
    }
    
    var a1 = data1.getAngle();
    var a2 = data2.getAngle();
    tol = Compare.getAngleTolerance();
    if (Math.abs(a1 - a2) > tol) {
        return false;
    }

    return true;
};

Compare.compareRadialDimension = function(dim1, dim2) {
    var cp1, cp2;
    
    if(! Compare.compareDimension(dim1, dim2)){
        return false;
    }

    var tol = Compare.getDistanceTolerance();
    
    cp1 = dim1.getChordPoint();
    cp2 = dim2.getChordPoint();
    if (cp1.getDistanceTo(cp2) > tol) {
        return false;
    }

    cp1 = dim1.getData().getCenter();
    cp2 = dim2.getData().getCenter();
    if (cp1.getDistanceTo(cp2) > tol) {
        return false;
    }
    
    return true;
};

Compare.compareRotatedDimension = function(dim1, dim2) {
    if(! Compare.compareDimension(dim1, dim2)){
        return false;
    }

    var a1 = dim1.getAngle();
    var a2 = dim2.getAngle();
    var tol = Compare.getAngleTolerance();
    if (Math.abs(a1 - a2) > tol) {
        return false;
    }
    
    return true;
};

Compare.compareLeaderEntity = function(e1, e2) {
    var c1 = e1.countVertices();
    var c2 = e2.countVertices();
    if (c1 != c2) {
        return false;
    }
    
    var tol = Compare.getDistanceTolerance();
    
    var sp1 = e1.getStartPoint();
    var sp2 = e2.getStartPoint();
    if (sp1.getDistanceTo(sp2) > tol) {
        return false;
    }
    
    var ep1 = e1.getEndPoint();
    var ep2 = e2.getEndPoint();
    if (ep1.getDistanceTo(ep2) > tol) {
        return false;
    }
    
    for (var i=0; i<c1; ++i) {
        var v1 = e1.getVertexAt(i);
        var v2 = e2.getVertexAt(i);
        if (v1.getDistanceTo(v2) > tol) {
            return false;
        }
    }

    return true;
};

Compare.compareOrdinateDimension = function(dim1, dim2) {
    if(! Compare.compareDimension(dim1, dim2)){
        return false;
    }

    var tol = Compare.getDistanceTolerance();
    var lp1 = dim1.getLeaderEndPoint();
    var lp2 = dim2.getLeaderEndPoint();
    if (lp1.getDistanceTo(lp2) > tol) {
        return false;
    }

    var dp1 = dim1.getDefiningPoint();
    var dp2 = dim2.getDefiningPoint();
    if (dp1.getDistanceTo(dp2) > tol) {
        return false;
    }
    
    var o1 = dim1.getData().getOrigin();
    var o2 = dim2.getData().getOrigin();
    if (o1.getDistanceTo(o2) > tol) {
        return false;
    }

    return true;
};

Compare.compareDiametricDimension = function(dim1, dim2) {
    if(! Compare.compareDimension(dim1, dim2)){
        return false;
    }

    var tol = Compare.getDistanceTolerance();
    
    var cp1 = dim1.getChordPoint();
    var cp2 = dim2.getChordPoint();
    if (cp1.getDistanceTo(cp2) > tol) {
        return false;
    }

    var fcp1 = dim1.getFarChordPoint();
    var fcp2 = dim2.getFarChordPoint();
    if (fcp1.getDistanceTo(fcp2) > tol) {
        return false;
    }

    return true;
};

Compare.compareAlignedDimension = function(dim1, dim2) {
    var ep1, ep2;
    
    if(! Compare.compareDimension(dim1, dim2)){
        return false;
    }
    
    var tol = Compare.getDistanceTolerance();
    
    ep1 = dim1.getExtensionPoint1();
    ep2 = dim2.getExtensionPoint1();
    if (ep1.getDistanceTo(ep2) > tol) {
        return false;
    }
    ep1 = dim1.getExtensionPoint2();
    ep2 = dim2.getExtensionPoint2();
    if (ep1.getDistanceTo(ep2) > tol) {
        return false;
    }

    return true;
};

Compare.compareText = function(text1, text2) {
    var plainText1 = text1.getPlainText();
    var plainText2 = text2.getPlainText();
    var pos1 = text1.getPosition();
    var pos2 = text2.getPosition();
    var tol = Compare.getDistanceTolerance();
    var fontName1 = text1.getFontName();
    var fontName2 = text2.getFontName();
    if(plainText1 == plainText2
            && pos1.getDistanceTo(pos2) <= tol && fontName1 == fontName2){
        return true;
    }
    return false;
};

Compare.compareCircle = function(circle1, circle2) {
    if (!Compare.compareCenter(circle1, circle2)) {
        return false;
    }
    if (!Compare.compareRadius(circle1, circle2)) {
        return false;
    }
    return true;
};

Compare.compareImage = function(image1, image2) {
    var tol = Compare.getDistanceTolerance();
    var h1 = image1.getHeight();
    var h2 = image2.getHeight();
    if (Math.abs(h1 - h2) > tol) {
        return false;
    }
    var w1 = image1.getWidth();
    var w2 = image2.getWidth();
    if (Math.abs(w1 - w2) > tol) {
        return false;
    }
    return true;
};

Compare.comparePoint = function(point1, point2) {
    var pos1 = point1.getPosition();
    var pos2 = point2.getPosition();
    var tol = Compare.getDistanceTolerance();
    if (pos1.getDistanceTo(pos2) > tol) {
        return false;
    }
    return true;
};

Compare.comparePolyline = function(polyline1, polyline2) {
    var segments1 = polyline1.countSegments();
    var segments2 = polyline2.countSegments();
    if(segments1 != segments2){
        return false;
    }
    
    for (var i=0; i<segments1; ++i) {
        var shape1 = polyline1.getSegmentAt(i);
        var shape2 = polyline2.getSegmentAt(i);
        if (Compare.compareShape(shape1, shape2) == false) {
            return false;
        }
    }
    return true;
};

Compare.compareSolid = function(solid1, solid2) {
    var tol = Compare.getDistanceTolerance();
    for (var i = 0; i < solid1.countVertices(); ++i) {
        if (solid1.getVertexAt(i).getDistanceTo(solid2.getVertexAt(i)) > tol) {
            return false;
        }
    }
    return true;
};

Compare.compareSpline = function(spline1, spline2) {
    var cps1 = spline1.getControlPoints();
    var cps2 = spline2.getControlPoints();
    if (cps1.length != cps2.length) {
        return false;
    }
    var tol = Compare.getDistanceTolerance();
    for (var i = 0; i < cps1.length; ++i) {
        if (cps1[i].getDistanceTo(cps2[i]) > tol) {
            return false;
        }
    }
    return true;
};

Compare.compareHatch = function(hatch1, hatch2) {
    var distTol = Compare.getDistanceTolerance();
    var data1 = hatch1.getData();
    var data2 = hatch2.getData();
    var s1 = data1.getScale();
    var s2 = data2.getScale();
    if (Math.abs(s1 - s2) > distTol) {
        return false;
    }
    
    var angTol = Compare.getAngleTolerance();
    var a1 = data1.getAngle();
    var a2 = data2.getAngle();
    if (Math.abs(a1 - a2) > angTol) {
        return false;
    }
    return true;
};

Compare.compareEllipse = function(ellipse1, ellipse2) {
    if (!Compare.compareCenter(ellipse1, ellipse2)) {
        return false;
    }
    if (!Compare.compareAngle(ellipse1, ellipse2)) {
        return false;
    }    

    var ratio1 = ellipse1.getRatio();
    var ratio2 = ellipse2.getRatio();
    var tol = Compare.getDistanceTolerance();
    if (Math.abs(ratio1 - ratio2) > tol) {
        return false;
    }

    var mp1 = ellipse1.getMajorPoint();
    var mp2 = ellipse2.getMajorPoint();
    if (mp1.getDistanceTo(mp2) > tol) {
        return false;
    }
    
    return true;
};

Compare.compareArc = function(arc1, arc2) {
    if (!Compare.compareCenter(arc1, arc2)) {
        return false;
    }
    if (!Compare.compareRadius(arc1, arc2)) {
        return false;
    }
    if (!Compare.compareAngle(arc1, arc2)) {
        return false;
    }
    return true;
};

Compare.compareBlockRef = function(block1, block2) {
    var tol = Compare.getDistanceTolerance();
    var atol = Compare.getAngleTolerance();

    var data1 = block1.getData();
    var data2 = block2.getData();

    var s1 = data1.getScaleFactors();
    var s2 = data2.getScaleFactors();
    if (s1.getDistanceTo(s2) > tol) {
        return false;
    }

    var p1 = data1.getPosition();
    var p2 = data2.getPosition();
    if (p1.getDistanceTo(p2) > tol) {
        return false;
    }

    var a1 = data1.getRotation();
    var a2 = data2.getRotation();
    if (Math.abs(a1 - a2) > atol) {
        return false;
    }

    var b1 = data1.getReferencedBlockName();
    var b2 = data2.getReferencedBlockName();
    if (b1!==b2) {
        return false;
    }

    return true;
};

Compare.compareColor = function(clr1, clr2) {
    if (clr1.mode === RColor.ByLayer) {
        return clr2.mode === RColor.ByLayer;
    }
    if (clr1.mode === RColor.ByBlock) {
        return clr2.mode === RColor.ByBlock;
    }
    return clr1.mode === clr2.mode && clr1.equals(clr2);
};

Compare.compareRadius = function(e1, e2) {
    var r1 = e1.getRadius();
    var r2 = e2.getRadius();
    var tol = Compare.getDistanceTolerance();
    if (Math.abs(r1 - r2) > tol) {
        return false;
    }
    return true;
};

Compare.compareCenter = function(e1, e2) {
    var c1 = e1.getCenter();
    var c2 = e2.getCenter();
    var tol = Compare.getDistanceTolerance();
    if (c1.getDistanceTo(c2) > tol) {
        return false;
    }
    return true;
};

Compare.compareProperty = function(propertyId, entity1, entity2) {
    var pt = new RPropertyTypeId(propertyId);
    var prop1 = entity1.getProperty(pt)[0];
    var prop2 = entity2.getProperty(pt)[0];
    if (prop1 != prop2) {
        return false;
    }
    return true;
};

Compare.compareAngle = function(e1, e2) {
    var sa1 = e1.getStartAngle();
    var sa2 = e2.getStartAngle();
    var ea1 = e1.getEndAngle();
    var ea2 = e2.getEndAngle();
    var rev1 = e1.isReversed();
    var rev2 = e2.isReversed();
    var tol = Compare.getAngleTolerance();
    if (rev1 === rev2) {
        if (Math.abs(sa1 - sa2) > tol ||
          Math.abs(ea1 - ea2) > tol) {
            return false;
        }
    } else {
        if (Math.abs(sa1 - ea2) > tol ||
          Math.abs(ea1 - sa2) > tol) {
            return false;
        }
    }
    return true;
};

Compare.setDistanceTolerance = function(tol){
    if(isString(tol)){
        Compare.distanceTolerance = tol.toFloat();
    }
    Compare.distanceTolerance = tol;
    Compare.updateDistanceTolCombo();
};

Compare.getDistanceTolerance = function(){
    if(isString(Compare.distanceTolerance)){
        Compare.distanceTolerance = Compare.distanceTolerance.toFloat();
    }
    return Compare.distanceTolerance;
};

Compare.setAngleTolerance = function(tol){
    Compare.angleTolerance = tol;
    Compare.updateAngleTolCombo();
};

Compare.getAngleTolerance = function(){
    return Compare.angleTolerance;
};

