/**
 * Copyright (c) 2011-2018 by Andrew Mustun. All rights reserved.
 * 
 * This file is part of the QCAD project.
 *
 * QCAD is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * QCAD is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with QCAD.
 */

include("scripts/Modify/Modify.js");
include("scripts/ShapeAlgorithms.js");

function BreakOutManual(guiAction) {
    Modify.call(this, guiAction);

    this.entity = undefined;
    this.shape = undefined;
    this.ceids = [];
    this.point1 = undefined;
    this.point2 = undefined;
    this.point3 = undefined;
    this.point4 = undefined;
    this.removeSegment = true;

    this.setUiOptions("BreakOutManual.ui");
}

BreakOutManual.prototype = new Modify();

BreakOutManual.State = {
    SettingShape : 0,
    SettingPoint1 : 1,
    SettingPoint2 : 2,
    SelectCircleEllipsePart : 3
};

BreakOutManual.prototype.beginEvent = function() {
    Modify.prototype.beginEvent.call(this);
    this.setState(BreakOutManual.State.SettingShape);
};

BreakOutManual.prototype.escapeEvent = function() {
    switch (this.state) {
    case BreakOutManual.State.SettingShape:
        EAction.prototype.escapeEvent.call(this);
        return;
    case BreakOutManual.State.SettingPoint1:
        this.setState(BreakOutManual.State.SettingShape);
        break;
    case BreakOutManual.State.SettingPoint2:
        this.setState(BreakOutManual.State.SettingPoint1);
        break;
    case BreakOutManual.State.SelectCircleEllipsePart:
        this.setState(BreakOutManual.State.SettingShape);
        break;
    }
};

BreakOutManual.prototype.setState = function(state) {
    Modify.prototype.setState.call(this, state);
    var di = this.getDocumentInterface();

    var appWin = RMainWindowQt.getMainWindow();
    switch (this.state) {
    case BreakOutManual.State.SettingShape:
        di.setClickMode(RAction.PickEntity);
        var trFirstPoint;
        if (RSpline.hasProxy() && RPolyline.hasProxy()) {
            trFirstPoint = qsTr("Choose line, arc, circle, ellipse, spline or polyline to break up");
        }
        else {
            trFirstPoint = qsTr("Choose line, arc, circle or ellipse to break up");
        }
        this.setCommandPrompt(trFirstPoint);
        this.setLeftMouseTip(trFirstPoint);
        this.setRightMouseTip(EAction.trCancel);
        this.ceids = [];
        break;
    case BreakOutManual.State.SettingPoint1:
        this.point2 = undefined;
        di.setClickMode(RAction.PickCoordinate);
        var trSecondPoint = qsTr("First break point");
        this.setCommandPrompt(trSecondPoint);
        this.setLeftMouseTip(trSecondPoint);
        this.setRightMouseTip(EAction.trDone);
        break;
    case BreakOutManual.State.SettingPoint2:
        this.point4 = undefined;
        di.setClickMode(RAction.PickCoordinate);
        var trThirdPoint = qsTr("Second break point");
        this.setCommandPrompt(trThirdPoint);
        this.setLeftMouseTip(trThirdPoint);
        this.setRightMouseTip(EAction.trDone);
        break;
    case BreakOutManual.State.SelectCircleEllipsePart:
        di.setClickMode(RAction.PickEntity);
        var cepos = qsTr("Click the part of the circle or ellipse to remove");
        this.setCommandPrompt(cepos);
        this.setLeftMouseTip(cepos);
        this.setRightMouseTip(EAction.trDone);
        break;
    }

    this.setCrosshairCursor();
    EAction.showSnapTools();
};

BreakOutManual.prototype.pickEntity = function(event, preview) {
    var di = this.getDocumentInterface();
    var doc = this.getDocument();
    var entityId = this.getEntityId(event, preview);
    var entity = doc.queryEntity(entityId);
    var pos = event.getModelPosition();

    if (isNull(entity)) {
        return;
    }

    this.entity = entity;

    switch (this.state) {
    case BreakOutManual.State.SettingShape:
        var cond = isLineBasedEntity(entity) ||
            isArcEntity(entity) ||
            isCircleEntity(entity) ||
            isEllipseEntity(entity) ||
            (RSpline.hasProxy() && isSplineEntity(entity)) ||
            (RPolyline.hasProxy() && isPolylineEntity(entity));

        if (!cond) {
            if (!preview) {
                if (RSpline.hasProxy() && RPolyline.hasProxy()) {
                    EAction.warnNotLineArcCircleEllipseSplinePolyline();
                }
                else {
                    EAction.warnNotLineArcCircleEllipse();
                }
            }
            break;
        }
        else {
            di.highlightEntity(this.entity.getId());
        }

        if (!EAction.assertEditable(entity, preview)) {
            break;
        }
        if (!preview) {
            this.shape = entity.getClosestShape(pos);
            this.setState(BreakOutManual.State.SettingPoint1);
        }
        break;
    case BreakOutManual.State.SelectCircleEllipsePart:
        di.highlightEntity(this.entity.getId());
        if (!preview) {
            if (this.ceids.indexOf(this.entity.getId())!==-1) {
                var op = new RDeleteObjectOperation(this.entity);
                op.setTransactionGroup(doc.getTransactionGroup());
                if (!isNull(op)) {
                    di.applyOperation(op);
                }
            }
            this.setState(BreakOutManual.State.SettingShape);
        }
        break;
    }
};

BreakOutManual.prototype.pickCoordinate = function(event, preview) {
    var di = this.getDocumentInterface();
    var doc = this.getDocument();
    var line;
    var op;

    if (isNull(this.shape)) {
        return;
    }
    switch (this.state) {
    case BreakOutManual.State.SettingPoint1:
        this.point1 = event.getModelPosition();
        if (!isValidVector(this.point1)) {
            return;
        }
        this.point2 = this.shape.getClosestPointOnShape(this.point1, true);
        if (!isValidVector(this.point2)) {
            if (this.point1.getDistanceTo(this.entity.getStartPoint()) <= this.point1.getDistanceTo(this.entity.getEndPoint())) {
                this.point2 = this.entity.getStartPoint();
            } else {
                this.point2 = this.entity.getEndPoint();
            }
            //return;
        }
        di.highlightEntity(this.entity.getId());

        if (preview) {
            line = new RLine(this.point1, this.point2);
            di.addAuxShapeToPreview(line);
        } else  {
            this.setState(BreakOutManual.State.SettingPoint2);
        }
        break;

    case BreakOutManual.State.SettingPoint2:
        this.point3 = event.getModelPosition();
        if (!isValidVector(this.point3)) {
            return;
        }
        this.point4 = this.shape.getClosestPointOnShape(this.point3, true);
        if (!isValidVector(this.point4)) {
            if (this.point3.getDistanceTo(this.entity.getStartPoint()) <= this.point3.getDistanceTo(this.entity.getEndPoint())) {
                this.point4 = this.entity.getStartPoint();
            } else {
                this.point4 = this.entity.getEndPoint();
            }
            //return;
        }
        di.highlightEntity(this.entity.getId());

        if (preview) {
            line = new RLine(this.point3, this.point4);
            di.addAuxShapeToPreview(line);
        } else  {
            op = this.getOperation(false);
            if (!isNull(op)) {
                doc.startTransactionGroup();
                op.setTransactionGroup(doc.getTransactionGroup());
                var t = di.applyOperation(op);

                if ((isCircleEntity(this.entity) || isFullEllipseEntity(this.entity)) && this.removeSegment) {
                    if (this.point2.equalsFuzzy(this.point4)) {
                        this.setState(BreakOutManual.State.SettingShape);
                    } else {
                        // remember IDs of added entities from transaction:
                        // used to make sure user cannot delete another entity:
                        this.ceids = t.getAffectedObjects();
                        this.setState(BreakOutManual.State.SelectCircleEllipsePart);
                    }
                } else {
                    this.setState(BreakOutManual.State.SettingShape);
                }
            }
        }
        break;
	}
};

BreakOutManual.prototype.getOperation = function(preview) {
    //var newSegments = BreakOutManual.autoTrim(this.shape, this.point2, this.point4);
    var newSegments = ShapeAlgorithms.autoSplitManual(this.shape, undefined, undefined, this.point2, this.point4, RVector.getAverage(this.point2, this.point4));

    if (isNull(newSegments)) {
        return undefined;
    }

    var op = new RAddObjectsOperation();
    op.setText(this.getToolTitle());
    var e;

    // replace circle with arc:
    if (isCircleEntity(this.entity) || isFullEllipseEntity(this.entity)) {
        op.deleteObject(this.entity);
        if (!isNull(newSegments[2])) {
            e = shapeToEntity(this.entity.getDocument(), newSegments[2]);
            if (!isNull(e)) {
                e.copyAttributesFrom(getPtr(this.entity));
                op.addObject(e, false);
            }
        }
    }

    // change existing entity into segment if we keep the segment,
    // otherwise delete existing entity
    else {
        if (this.removeSegment) {
            // delete entity completely:
            op.deleteObject(this.entity);
        }
        else {
            this.entity.setShape(newSegments[2]);
            op.addObject(this.entity, false);
        }
    }

    if (!isNull(newSegments[0])) {
        e = shapeToEntity(this.entity.getDocument(), newSegments[0]);
        if (!isNull(e)) {
            e.copyAttributesFrom(getPtr(this.entity));
            op.addObject(e, false);
        }
    }

    if (!isNull(newSegments[1])) {
        e = shapeToEntity(this.entity.getDocument(), newSegments[1])
        if (!isNull(e)) {
            e.copyAttributesFrom(getPtr(this.entity));
            op.addObject(e, false);
        }
    }

    return op;
};

BreakOutManual.prototype.slotRemoveSegmentChanged = function(value) {
    this.removeSegment = value;
};
