/**
 * This file is part of the QCAD/CAM software.
 * Do NOT edit this file. Your changes will be lost when the software 
 * is updated or reinstalled. 
 * For details, please refer to the file README.txt in this directory.
 */

/**
 * Include definition of class CamExporterV2 from QCAD/CAM plugin:
 */
include("scripts/Cam/CamExportV2/CamExporterV2.js");

/**
 * This is a base class for G-Code configurations.
 * 
 * Do not edit this class. 
 * Instead, create your own derivation as shown in GodeMM.js, GCodeIN.js, ...
 */
function GCodeBase(cadDocumentInterface, camDocumentInterface) {
    // call constructor of base class 'CamExporterV2':
    CamExporterV2.call(this, cadDocumentInterface, camDocumentInterface);

    if (isNull(cadDocumentInterface)) {
        // constructor used as prototype:
        return;
    }

    // these variables are only set if they have not yet been initialized
    // by a derived configuration:
    this.decimals = 4;
    // output unit:
    this.unit = RS.None;
    // true to output computed offset path coordinates:
    this.outputOffsetPath = false;
    // first line number:
    this.lineNumber = 10;
    // line number increment:
    this.lineNumberIncrement = 10;

    // home position
    // (can for example be used in header / footer or for tool changes):
    this.xHomePosition = 0;
    this.yHomePosition = 0;
    this.zHomePosition = 50;

    // Z levels:
    this.zClearance = 1.0;
    this.zCuttingDepth = -1.0;

    // true: split full circles in halves
    this.splitFullCircles = false;

    // true: always write G1, even if G mode does not change:
    this.alwaysWriteG1 = false;

    // line ending:
    this.lineEnding = "\n";

    // Array of file extensions which can be used for the exported file.
    // The user can choose the desired extension when exporting a gile.
    this.fileExtensions = [ "nc", "gcode", "cnc", "ngc", "txt", "prg" ];

    // variables:
    //                    name,                  ID,                     always, prefix, decimals, options
    this.registerVariable("inputFileName",       "INFILENAME",           true,  "",  0);
    this.registerVariable("inputFilePath",       "INFILEPATH",           true,  "",  0);
    this.registerVariable("fileName",            "FILENAME",             true,  "",  0);
    this.registerVariable("filePath",            "FILEPATH",             true,  "",  0);
    this.registerVariable("dateTime",            "DATETIME",             true,  "",  0);

    this.registerVariable("lineNumber",          "N",                    true,  "N", 0);
                                                                         
    this.registerVariable("spindleSpeed",        "S",                    true,  "S", 0);
    this.registerVariable("feedRate",            "F",                    false, "F", 0);
    this.registerVariable("plungeRate",          "FP",                   false, "F", 0);
                                                                         
    this.registerVariable("xHomePosition",       "XH",                   true,  "X", "DEFAULT", "DEFAULT");
    this.registerVariable("yHomePosition",       "YH",                   true,  "Y", "DEFAULT", "DEFAULT");
    this.registerVariable("zHomePosition",       "ZH",                   true,  "Z", "DEFAULT", "DEFAULT");

    this.registerVariable("zSafety",             "ZS",                   true,  "Z", "DEFAULT", "DEFAULT");
    this.registerVariable("zClearance",          "ZU",                   true,  "Z", "DEFAULT", "DEFAULT");
    this.registerVariable("zClearancePass",      "ZUP",                  true,  "Z", "DEFAULT", "DEFAULT");
    this.registerVariable("zStart",              "Z_START",              true,  "Z", "DEFAULT", "DEFAULT");
    this.registerVariable("zEnd",                "Z_END",                true,  "Z", "DEFAULT", "DEFAULT");
    this.registerVariable("zCuttingDepth",       "ZD",                   true,  "Z", "DEFAULT", "DEFAULT");

    this.registerVariable("xFirstPosition",      "XF",                   true,  "X", "DEFAULT", "DEFAULT");
    this.registerVariable("yFirstPosition",      "YF",                   true,  "Y", "DEFAULT", "DEFAULT");

    this.registerVariable("xStartPosition",      "X1",                   true,  "X", "DEFAULT", "DEFAULT");
    this.registerVariable("yStartPosition",      "Y1",                   true,  "Y", "DEFAULT", "DEFAULT");
    this.registerVariable("zStartPosition",      "Z1",                   true,  "Z", "DEFAULT", "DEFAULT");

    this.registerVariable("startAngle",          "A1",                   true,  "A", "DEFAULT", "DEFAULT");
    this.registerVariable("endAngle",            "A2",                   true,  "A", "DEFAULT", "DEFAULT");

    this.registerVariable("xPosition",           "X",                    false, "X", "DEFAULT", "DEFAULT");
    this.registerVariable("yPosition",           "Y",                    false, "Y", "DEFAULT", "DEFAULT");
    this.registerVariable("zPosition",           "Z",                    false, "Z", "DEFAULT", "DEFAULT");

    this.registerVariable("xRelPosition",        "XR",                   true,  "X", "DEFAULT", "DEFAULT");
    this.registerVariable("yRelPosition",        "YR",                   true,  "Y", "DEFAULT", "DEFAULT");
    this.registerVariable("zRelPosition",        "ZR",                   true,  "Z", "DEFAULT", "DEFAULT");

    this.registerVariable("iArcCenterInc",       "I",                    true,  "I", "DEFAULT", "DEFAULT");
    this.registerVariable("jArcCenterInc",       "J",                    true,  "J", "DEFAULT", "DEFAULT");
    this.registerVariable("iArcCenterAbs",       "IA",                   true,  "I", "DEFAULT", "DEFAULT");
    this.registerVariable("jArcCenterAbs",       "JA",                   true,  "J", "DEFAULT", "DEFAULT");
    this.registerVariable("arcRadius",           "RADIUS",               true,  "", "DEFAULT", "DEFAULT");
    this.registerVariable("arcDiameter",         "DIAMETER",             true,  "", "DEFAULT", "DEFAULT");
    this.registerVariable("arcSweep",            "SWEEP",                true,  "", "DEFAULT", "DEFAULT");
                                                                         
    this.registerVariable("tool",                "T",                    true,  "T", 0);
    this.registerVariable("toolRadius",          "TR",                   true,  "",  "DEFAULT", "DEFAULT");
    this.registerVariable("toolDiameter",        "TD",                   true,  "",  "DEFAULT", "DEFAULT");
                                                                                
    // Toolpath order: order number of toolpath (can be any number, increasing):
    this.registerVariable("toolpathOrder",       "TOOLPATH_ORDER",       true,  "",  0);

    // Toolpath index: index of toolpath (0, 1, 2, ...):
    this.registerVariable("toolpathIndex",       "TOOLPATH_INDEX",       true,  "",  0);
    //this.registerVariable("toolpathIndex1",      "TOOLPATH_INDEX_1",     true,  "",  0);

    // Tool calls: number of calls for current tool, starting with 1
    this.registerVariable("toolCalls",           "TOOL_CALLS",           true,  "",  0);

    this.registerVariable("toolpathName",        "TOOLPATH_NAME",        true,  "",  0);
    this.registerVariable("programName",         "PROGRAM_NAME",         true,  "",  0);

    this.registerVariable("xMin",                "X_MIN",                true,  "",  "DEFAULT", "DEFAULT");
    this.registerVariable("xMax",                "X_MAX",                true,  "",  "DEFAULT", "DEFAULT");
    this.registerVariable("yMin",                "Y_MIN",                true,  "",  "DEFAULT", "DEFAULT");
    this.registerVariable("yMax",                "Y_MAX",                true,  "",  "DEFAULT", "DEFAULT");
    this.registerVariable("zMin",                "Z_MIN",                true,  "",  "DEFAULT", "DEFAULT");
    this.registerVariable("zMax",                "Z_MAX",                true,  "",  "DEFAULT", "DEFAULT");

    // output blocks:

    // header / footer before / after output:
    this.header = [];
    this.footer = [
        "[N] M30"
    ];

    // header / footer before / after tool change:
    this.toolHeader = [
        "[N] [T] M6",
        "[N] [S] M03"
    ];
    this.toolFooter = [];

    // header / footer before / after each toolpath (can be multiple contours):
    this.toolpathHeader = [];
    this.toolpathFooter = [];

    // header / footer before / after each contour in a toolpath:
    this.contourHeader = [];
    this.contourFooter = [];

    // header / footer before / after single Z pass:
    this.singleZPassHeader = [];
    this.singleZPassFooter = [];

    // header / footer before / after mutliple Z passes:
    this.multiZPassHeader = [];
    this.multiZPassFooter = [];

    // header / footer before / after first pass of mutliple or single Z pass(es):
    this.zPassFirstHeader = [];
    this.zPassFirstFooter = [];

    // header / footer before / after each pass of mutliple Z passes:
    this.zPassHeader = [];
    this.zPassFooter = [];

    // footer after last pass of mutliple Z passes:
    this.zPassLastFooter = [];

    // rapid moves:
    this.rapidMove =                 "[N] G0 [X] [Y]";
    this.rapidMoveZ =                "[N] G0 [Z]";

    // linear moves:
    this.firstLinearMove =           "[N] G1 [X] [Y] [F]";
    this.linearMove =                "[N] [X] [Y] [F]";

    // linear lead in / out:
    // these default to this.linearMove:
    this.linearLeadIn = undefined;
    this.linearLeadOut = undefined;

    // linear Z moves:
    this.firstLinearMoveZ =          "[N] G1 [Z] [F]";
    this.linearMoveZ =               "[N] [Z] [F]";

    // point moves for drilling:
    this.firstPointMoveZ =           this.firstLinearMoveZ;
    this.pointMoveZ =                this.linearMoveZ;

    // circular moves:
    this.firstArcCWMove =            "[N] G2 [X] [Y] [I] [J] [F]";
    this.arcCWMove =                 "[N] G2 [X] [Y] [I] [J] [F]";

    this.firstArcCCWMove =           "[N] G3 [X] [Y] [I] [J] [F]";
    this.arcCCWMove =                "[N] G3 [X] [Y] [I] [J] [F]";

    // tool compensation on:
    this.linearMoveCompensationLeft = [
        "[N] [F!]",
        "[N] G41 [X] [Y]"
    ];
    this.linearMoveCompensationRight = [
        "[N] [F!]",
        "[N] G42 [X] [Y]"
    ];

    // tool compensation off:
    this.linearMoveCompensationOff = "[N] G40 [X] [Y]";

    // command to execute after writing file:
    this.runCommand = "";

    this.alwaysWriteG1 = false;

    this.debugging = false;
}

/**
 * Configuration 'GCodeBase' is derived from class 'CamExporterV2'. All configurations
 * _must_ be (directly or indirectly) derived from CamExporterV2 to be valid configurations.
 */
GCodeBase.prototype = new CamExporterV2();
GCodeBase.displayName = "";

GCodeBase.prototype.postInit = function(dialog) {
    var ret = CamExporterV2.prototype.postInit.call(this, dialog);

    if (this.alwaysWriteG1===true) {
        this.cadDocument.setVariable(Cam.getCurrentVariablePrefix() + "AlwaysWriteG1", true);
    }

    // save original text blocks for skipping G1:
    // needed to restore if always write G1 is switched off:
    if (isNull(this.linearMoveOri)) {
        this.linearMoveOri = this.linearMove;
        this.linearMoveZOri = this.linearMoveZ;
        this.pointMoveZOri = this.pointMoveZ;
    }

    return ret;
};

GCodeBase.prototype.initConfigDialog = function(dialog) {
    // add options for laser on / off:
    var group = dialog.findChild("GroupCustom");
    group.title = qsTr("G-Code");

    // get QVBoxLayout:
    var vBoxLayout = group.layout();

    // add checkbox to force G1:
    var hBoxLayout = new QHBoxLayout(null);
    vBoxLayout.addLayout(hBoxLayout, 0);

    var cbAlwaysWriteG1 = new QCheckBox(qsTr("Always write G1"));
    cbAlwaysWriteG1.objectName = "AlwaysWriteG1";
    hBoxLayout.addWidget(cbAlwaysWriteG1, 0,0);
};

GCodeBase.prototype.writeFile = function(fileName) {
    if (this.getGlobalOption("AlwaysWriteG1", false)===true) {
        this.linearMove = this.firstLinearMove;
        this.linearMoveZ = this.firstLinearMoveZ;
        this.pointMoveZ = this.firstPointMoveZ;
    }
    else {
        this.linearMove = this.linearMoveOri;
        this.linearMoveZ = this.linearMoveZOri;
        this.pointMoveZ = this.pointMoveZOri;
    }

    return CamExporterV2.prototype.writeFile.call(this, fileName);
};
