/*
 * Copyright 2015,  Sven Stork
 */


/*jslint vars: true, plusplus: true, devel: true, nomen: true, regexp: true, indent: 4, maxerr: 100   */
/*global $, Folder, charIDToTypeID, ActionDescriptor, ActionReference, stringIDToTypeID, executeAction, DialogModes, app, executeActionGet, ActionList, activeDocument */
/*jshint -W004 */

/****************************************************************************/
/*                                ACTIONS                                   */
/****************************************************************************/

/*
 * We cannot use Object freesze, therfore be carefull with not changing the values accidentialy   
 */
var TAB_ID = {
    // this struct need to be in sync with the definition in main.js
    LUMINOSITY_MASKS: 0,
    SATURATION_MASKS: 1,
    SUPPORT: 2
}


function /* void */ __ss_ilm_action_createSaturationLayer() {
    // create empty layer
    var idMk = charIDToTypeID("Mk  ");
    var desc550 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref403 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    ref403.putClass(idLyr);
    desc550.putReference(idnull, ref403);
    var idUsng = charIDToTypeID("Usng");
    var desc551 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc551.putString(idNm, "__ss_ilm_saturation");
    var idLyr = charIDToTypeID("Lyr ");
    desc550.putObject(idUsng, idLyr, desc551);
    executeAction(idMk, desc550, DialogModes.NO);


    // applt image(ie., creat stamp visible layer)
    // =======================================================
    var idAppI = charIDToTypeID("AppI");
    var desc528 = new ActionDescriptor();
    var idWith = charIDToTypeID("With");
    var desc529 = new ActionDescriptor();
    var idT = charIDToTypeID("T   ");
    var ref384 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idRGB = charIDToTypeID("RGB ");
    ref384.putEnumerated(idChnl, idChnl, idRGB);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref384.putEnumerated(idLyr, idOrdn, idMrgd);
    desc529.putReference(idT, ref384);
    var idClcl = charIDToTypeID("Clcl");
    desc528.putObject(idWith, idClcl, desc529);
    executeAction(idAppI, desc528, DialogModes.NO);

    // convert current layer to HSB
    var idHsbP = charIDToTypeID("HsbP");
    var desc508 = new ActionDescriptor();
    var idInpt = charIDToTypeID("Inpt");
    var idClrS = charIDToTypeID("ClrS");
    var idRGBC = charIDToTypeID("RGBC");
    desc508.putEnumerated(idInpt, idClrS, idRGBC);
    var idOtpt = charIDToTypeID("Otpt");
    var idClrS = charIDToTypeID("ClrS");
    var idHSBl = charIDToTypeID("HSBl");
    desc508.putEnumerated(idOtpt, idClrS, idHSBl);
    executeAction(idHsbP, desc508, DialogModes.NO);

    // override with greem(saturation) channel 
    var idAppI = charIDToTypeID("AppI");
    var desc509 = new ActionDescriptor();
    var idWith = charIDToTypeID("With");
    var desc510 = new ActionDescriptor();
    var idT = charIDToTypeID("T   ");
    var ref368 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idGrn = charIDToTypeID("Grn ");
    ref368.putEnumerated(idChnl, idChnl, idGrn);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref368.putEnumerated(idLyr, idOrdn, idMrgd);
    desc510.putReference(idT, ref368);
    var idClcl = charIDToTypeID("Clcl");
    desc509.putObject(idWith, idClcl, desc510);
    executeAction(idAppI, desc509, DialogModes.NO);
}

function /* void */ __ss_ilm_action_createLuminosityLayer() {
    var psVersion = app.version.split("\.")

    if (psVersion[0] <= 14) {
        /* create black and white layer */
        var idMk = charIDToTypeID("Mk  ");
        var desc9 = new ActionDescriptor();
        var idnull = charIDToTypeID("null");
        var ref8 = new ActionReference();
        var idAdjL = charIDToTypeID("AdjL");
        ref8.putClass(idAdjL);
        desc9.putReference(idnull, ref8);
        var idUsng = charIDToTypeID("Usng");
        var desc10 = new ActionDescriptor();
        var idNm = charIDToTypeID("Nm  ");
        desc10.putString(idNm, "__ss_ilm_luminosity");
        var idType = charIDToTypeID("Type");
        var desc11 = new ActionDescriptor();
        var idpresetKind = stringIDToTypeID("presetKind");
        var idpresetKindType = stringIDToTypeID("presetKindType");
        var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
        desc11.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
        var idRd = charIDToTypeID("Rd  ");
        desc11.putInteger(idRd, 50);
        var idYllw = charIDToTypeID("Yllw");
        desc11.putInteger(idYllw, 50);
        var idGrn = charIDToTypeID("Grn ");
        desc11.putInteger(idGrn, 50);
        var idCyn = charIDToTypeID("Cyn ");
        desc11.putInteger(idCyn, 50);
        var idBl = charIDToTypeID("Bl  ");
        desc11.putInteger(idBl, 50);
        var idMgnt = charIDToTypeID("Mgnt");
        desc11.putInteger(idMgnt, 50);
        var iduseTint = stringIDToTypeID("useTint");
        desc11.putBoolean(iduseTint, false);
        var idtintColor = stringIDToTypeID("tintColor");
        var desc12 = new ActionDescriptor();
        var idRd = charIDToTypeID("Rd  ");
        desc12.putDouble(idRd, 225.000458);
        var idGrn = charIDToTypeID("Grn ");
        desc12.putDouble(idGrn, 211.000671);
        var idBl = charIDToTypeID("Bl  ");
        desc12.putDouble(idBl, 179.001160);
        var idRGBC = charIDToTypeID("RGBC");
        desc11.putObject(idtintColor, idRGBC, desc12);
        var idBanW = charIDToTypeID("BanW");
        desc10.putObject(idType, idBanW, desc11);
        var idAdjL = charIDToTypeID("AdjL");
        desc9.putObject(idUsng, idAdjL, desc10);
        executeAction(idMk, desc9, DialogModes.NO);
    } else {
        // >= PS CC 2014
        // create empty layer
        var idMk = charIDToTypeID("Mk  ");
        var desc550 = new ActionDescriptor();
        var idnull = charIDToTypeID("null");
        var ref403 = new ActionReference();
        var idLyr = charIDToTypeID("Lyr ");
        ref403.putClass(idLyr);
        desc550.putReference(idnull, ref403);
        var idUsng = charIDToTypeID("Usng");
        var desc551 = new ActionDescriptor();
        var idNm = charIDToTypeID("Nm  ");
        desc551.putString(idNm, "__ss_ilm_saturation");
        var idLyr = charIDToTypeID("Lyr ");
        desc550.putObject(idUsng, idLyr, desc551);
        executeAction(idMk, desc550, DialogModes.NO);


        // applt image(ie., creat stamp visible layer)
        // =======================================================
        var idAppI = charIDToTypeID("AppI");
        var desc528 = new ActionDescriptor();
        var idWith = charIDToTypeID("With");
        var desc529 = new ActionDescriptor();
        var idT = charIDToTypeID("T   ");
        var ref384 = new ActionReference();
        var idChnl = charIDToTypeID("Chnl");
        var idChnl = charIDToTypeID("Chnl");
        var idRGB = charIDToTypeID("RGB ");
        ref384.putEnumerated(idChnl, idChnl, idRGB);
        var idLyr = charIDToTypeID("Lyr ");
        var idOrdn = charIDToTypeID("Ordn");
        var idMrgd = charIDToTypeID("Mrgd");
        ref384.putEnumerated(idLyr, idOrdn, idMrgd);
        desc529.putReference(idT, ref384);
        var idClcl = charIDToTypeID("Clcl");
        desc528.putObject(idWith, idClcl, desc529);
        executeAction(idAppI, desc528, DialogModes.NO);

        // convert current layer to HSB
        var idHsbP = charIDToTypeID("HsbP");
        var desc508 = new ActionDescriptor();
        var idInpt = charIDToTypeID("Inpt");
        var idClrS = charIDToTypeID("ClrS");
        var idRGBC = charIDToTypeID("RGBC");
        desc508.putEnumerated(idInpt, idClrS, idRGBC);
        var idOtpt = charIDToTypeID("Otpt");
        var idClrS = charIDToTypeID("ClrS");
        var idHSBl = charIDToTypeID("HSBl");
        desc508.putEnumerated(idOtpt, idClrS, idHSBl);
        executeAction(idHsbP, desc508, DialogModes.NO);

        // override with greem(saturation) channel 
        var idAppI = charIDToTypeID("AppI");
        var desc509 = new ActionDescriptor();
        var idWith = charIDToTypeID("With");
        var desc510 = new ActionDescriptor();
        var idT = charIDToTypeID("T   ");
        var ref368 = new ActionReference();
        var idChnl = charIDToTypeID("Chnl");
        var idChnl = charIDToTypeID("Chnl");
        var idGrn = charIDToTypeID("Bl  ");
        ref368.putEnumerated(idChnl, idChnl, idGrn);
        var idLyr = charIDToTypeID("Lyr ");
        var idOrdn = charIDToTypeID("Ordn");
        var idMrgd = charIDToTypeID("Mrgd");
        ref368.putEnumerated(idLyr, idOrdn, idMrgd);
        desc510.putReference(idT, ref368);
        var idClcl = charIDToTypeID("Clcl");
        desc509.putObject(idWith, idClcl, desc510);
        executeAction(idAppI, desc509, DialogModes.NO);

    }
}

function /* void */ __ss_ilm_action_createHelperLayer(tabId) {
    if (TAB_ID.LUMINOSITY_MASKS == tabId) {
        __ss_ilm_action_createLuminosityLayer()
    } else if (TAB_ID.SATURATION_MASKS == tabId) {
        __ss_ilm_action_createSaturationLayer()
    }
}

/*
 * This method creates all layers for a low mask.
 * It creates a group which contains a BW layer to convert the
 * image to a black and white image and level layer to adjust the
 * amount of lows visible
 */
function /* void */ __ss_ilm_action_createHighMask(tabId) {
    /* clear existing selection */
    __ss_ilm_action_selectNone()

    /* create group */
    var idMk = charIDToTypeID("Mk  ");
    var desc6 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref5 = new ActionReference();
    var idlayerSection = stringIDToTypeID("layerSection");
    ref5.putClass(idlayerSection);
    desc6.putReference(idnull, ref5);
    var idUsng = charIDToTypeID("Usng");
    var desc7 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc7.putString(idNm, __ss_ilm_getILMGroupName());
    var idlayerSection = stringIDToTypeID("layerSection");
    desc6.putObject(idUsng, idlayerSection, desc7);
    executeAction(idMk, desc6, DialogModes.NO);

    /* move layer */
    var idmove = charIDToTypeID("move");
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref6 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref6.putEnumerated(idLyr, idOrdn, idTrgt);
    desc8.putReference(idnull, ref6);
    var idT = charIDToTypeID("T   ");
    var ref7 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idFrnt = charIDToTypeID("Frnt");
    ref7.putEnumerated(idLyr, idOrdn, idFrnt);
    desc8.putReference(idT, ref7);
    executeAction(idmove, desc8, DialogModes.NO);

    /* create helper layer */
    __ss_ilm_action_createHelperLayer(tabId)

    /* create levels layer */
    var idMk = charIDToTypeID("Mk  ");
    var desc13 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref9 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref9.putClass(idAdjL);
    desc13.putReference(idnull, ref9);
    var idUsng = charIDToTypeID("Usng");
    var desc14 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc14.putString(idNm, __ss_ilm_getHighLayerName());
    var idType = charIDToTypeID("Type");
    var desc15 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID("presetKind");
    var idpresetKindType = stringIDToTypeID("presetKindType");
    var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
    desc15.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
    var idLvls = charIDToTypeID("Lvls");
    desc14.putObject(idType, idLvls, desc15);
    var idAdjL = charIDToTypeID("AdjL");
    desc13.putObject(idUsng, idAdjL, desc14);
    executeAction(idMk, desc13, DialogModes.NO);
}

/*
 * This method creates a merged layer, desaturates it, applies
 * the differences of itselfs to itself and the inverts it. The
 * it creates the standard group and level layer.
 */
function /* void */ __ss_ilm_action_createMidMask(tabId) {
    /* clear existing selection */
    __ss_ilm_action_selectNone()

    /* create base layer */
    var idMk = charIDToTypeID("Mk  ");
    var desc18 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref10 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    ref10.putClass(idLyr);
    desc18.putReference(idnull, ref10);
    var idUsng = charIDToTypeID("Usng");
    var desc19 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc19.putString(idNm, "__ss_ilm_mid_base");
    var idLyr = charIDToTypeID("Lyr ");
    desc18.putObject(idUsng, idLyr, desc19);
    executeAction(idMk, desc18, DialogModes.NO);

    /* apply current image */
    var idAppI = charIDToTypeID("AppI");
    var desc20 = new ActionDescriptor();
    var idWith = charIDToTypeID("With");
    var desc21 = new ActionDescriptor();
    var idT = charIDToTypeID("T   ");
    var ref11 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idRGB = charIDToTypeID("RGB ");
    ref11.putEnumerated(idChnl, idChnl, idRGB);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref11.putEnumerated(idLyr, idOrdn, idMrgd);
    desc21.putReference(idT, ref11);
    var idClcl = charIDToTypeID("Clcl");
    desc20.putObject(idWith, idClcl, desc21);
    executeAction(idAppI, desc20, DialogModes.NO);

    // create helper layer
    if (TAB_ID.LUMINOSITY_MASKS == tabId) {
        /* desaturate layer */
        var idDstt = charIDToTypeID("Dstt");
        executeAction(idDstt, undefined, DialogModes.NO);
    } else if (TAB_ID.SATURATION_MASKS == tabId) {
        var idSlcC = charIDToTypeID("SlcC");
        var desc130 = new ActionDescriptor();
        var idpresetKind = stringIDToTypeID("presetKind");
        var idpresetKindType = stringIDToTypeID("presetKindType");
        var idpresetKindCustom = stringIDToTypeID("presetKindCustom");
        desc130.putEnumerated(idpresetKind, idpresetKindType, idpresetKindCustom);
        var idMthd = charIDToTypeID("Mthd");
        var idCrcM = charIDToTypeID("CrcM");
        var idAbsl = charIDToTypeID("Absl");
        desc130.putEnumerated(idMthd, idCrcM, idAbsl);
        var idClrC = charIDToTypeID("ClrC");
        var list21 = new ActionList();
        var desc131 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idRds = charIDToTypeID("Rds ");
        desc131.putEnumerated(idClrs, idClrs, idRds);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc131.putUnitDouble(idBlck, idPrc, -100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc131);
        var desc132 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idYlws = charIDToTypeID("Ylws");
        desc132.putEnumerated(idClrs, idClrs, idYlws);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc132.putUnitDouble(idBlck, idPrc, -100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc132);
        var desc133 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idGrns = charIDToTypeID("Grns");
        desc133.putEnumerated(idClrs, idClrs, idGrns);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc133.putUnitDouble(idBlck, idPrc, -100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc133);
        var desc134 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idCyns = charIDToTypeID("Cyns");
        desc134.putEnumerated(idClrs, idClrs, idCyns);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc134.putUnitDouble(idBlck, idPrc, -100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc134);
        var desc135 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idBls = charIDToTypeID("Bls ");
        desc135.putEnumerated(idClrs, idClrs, idBls);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc135.putUnitDouble(idBlck, idPrc, -100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc135);
        var desc136 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idMgnt = charIDToTypeID("Mgnt");
        desc136.putEnumerated(idClrs, idClrs, idMgnt);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc136.putUnitDouble(idBlck, idPrc, -100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc136);
        var desc137 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idWhts = charIDToTypeID("Whts");
        desc137.putEnumerated(idClrs, idClrs, idWhts);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc137.putUnitDouble(idBlck, idPrc, 100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc137);
        var desc138 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idNtrl = charIDToTypeID("Ntrl");
        desc138.putEnumerated(idClrs, idClrs, idNtrl);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc138.putUnitDouble(idBlck, idPrc, 100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc138);
        var desc139 = new ActionDescriptor();
        var idClrs = charIDToTypeID("Clrs");
        var idClrs = charIDToTypeID("Clrs");
        var idBlks = charIDToTypeID("Blks");
        desc139.putEnumerated(idClrs, idClrs, idBlks);
        var idBlck = charIDToTypeID("Blck");
        var idPrc = charIDToTypeID("#Prc");
        desc139.putUnitDouble(idBlck, idPrc, 100.000000);
        var idClrC = charIDToTypeID("ClrC");
        list21.putObject(idClrC, desc139);
        desc130.putList(idClrC, list21);
        executeAction(idSlcC, desc130, DialogModes.NO);
    }

    /* apply image inverse + difference*/
    var idAppI = charIDToTypeID("AppI");
    var desc22 = new ActionDescriptor();
    var idWith = charIDToTypeID("With");
    var desc23 = new ActionDescriptor();
    var idT = charIDToTypeID("T   ");
    var ref12 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idRGB = charIDToTypeID("RGB ");
    ref12.putEnumerated(idChnl, idChnl, idRGB);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref12.putEnumerated(idLyr, idOrdn, idMrgd);
    desc23.putReference(idT, ref12);
    var idInvr = charIDToTypeID("Invr");
    desc23.putBoolean(idInvr, true);
    var idClcl = charIDToTypeID("Clcl");
    var idClcn = charIDToTypeID("Clcn");
    var idDfrn = charIDToTypeID("Dfrn");
    desc23.putEnumerated(idClcl, idClcn, idDfrn);
    var idClcl = charIDToTypeID("Clcl");
    desc22.putObject(idWith, idClcl, desc23);
    executeAction(idAppI, desc22, DialogModes.NO);

    /* invert image */
    var idInvr = charIDToTypeID("Invr");
    executeAction(idInvr, undefined, DialogModes.NO);

    /* create group */
    var idMk = charIDToTypeID("Mk  ");
    var desc24 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref13 = new ActionReference();
    var idlayerSection = stringIDToTypeID("layerSection");
    ref13.putClass(idlayerSection);
    desc24.putReference(idnull, ref13);
    var idFrom = charIDToTypeID("From");
    var ref14 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref14.putEnumerated(idLyr, idOrdn, idTrgt);
    desc24.putReference(idFrom, ref14);
    executeAction(idMk, desc24, DialogModes.NO);

    /* rename group */
    var idsetd = charIDToTypeID("setd");
    var desc25 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref15 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref15.putEnumerated(idLyr, idOrdn, idTrgt);
    desc25.putReference(idnull, ref15);
    var idT = charIDToTypeID("T   ");
    var desc26 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc26.putString(idNm, __ss_ilm_getILMGroupName());
    var idLyr = charIDToTypeID("Lyr ");
    desc25.putObject(idT, idLyr, desc26);
    executeAction(idsetd, desc25, DialogModes.NO);

    /* create levels layer */
    // =======================================================
    var idMk = charIDToTypeID("Mk  ");
    var desc36 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref21 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref21.putClass(idAdjL);
    desc36.putReference(idnull, ref21);
    var idUsng = charIDToTypeID("Usng");
    var desc37 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc37.putString(idNm, __ss_ilm_getMidLayerName());
    var idType = charIDToTypeID("Type");
    var desc38 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID("presetKind");
    var idpresetKindType = stringIDToTypeID("presetKindType");
    var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
    desc38.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
    var idLvls = charIDToTypeID("Lvls");
    desc37.putObject(idType, idLvls, desc38);
    var idAdjL = charIDToTypeID("AdjL");
    desc36.putObject(idUsng, idAdjL, desc37);
    executeAction(idMk, desc36, DialogModes.NO);
}

/*
 * This method creates all layers for a low mask.
 * It creates a group which contains a BW layer to convert the
 * image to a black and white image, a invert layer to select
 * Lows instead of highlights  and level layer to adjust the
 * amount of Lows visible
 */
function /* void */ __ss_ilm_action_createLowMask(tabId) {
    /* clear existing selection */
    __ss_ilm_action_selectNone()

    /* create group */
    var idMk = charIDToTypeID("Mk  ");
    var desc6 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref5 = new ActionReference();
    var idlayerSection = stringIDToTypeID("layerSection");
    ref5.putClass(idlayerSection);
    desc6.putReference(idnull, ref5);
    var idUsng = charIDToTypeID("Usng");
    var desc7 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc7.putString(idNm, __ss_ilm_getILMGroupName());
    var idlayerSection = stringIDToTypeID("layerSection");
    desc6.putObject(idUsng, idlayerSection, desc7);
    executeAction(idMk, desc6, DialogModes.NO);

    /* move layer */
    var idmove = charIDToTypeID("move");
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref6 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref6.putEnumerated(idLyr, idOrdn, idTrgt);
    desc8.putReference(idnull, ref6);
    var idT = charIDToTypeID("T   ");
    var ref7 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idFrnt = charIDToTypeID("Frnt");
    ref7.putEnumerated(idLyr, idOrdn, idFrnt);
    desc8.putReference(idT, ref7);
    executeAction(idmove, desc8, DialogModes.NO);

    // create helper layer
    __ss_ilm_action_createHelperLayer(tabId)

    /* create invert layer */
    var idMk = charIDToTypeID("Mk  ");
    var desc2 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref1 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref1.putClass(idAdjL);
    desc2.putReference(idnull, ref1);
    var idUsng = charIDToTypeID("Usng");
    var desc3 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc3.putString(idNm, "__ss_ilm_invert");
    var idType = charIDToTypeID("Type");
    var idInvr = charIDToTypeID("Invr");
    desc3.putClass(idType, idInvr);
    var idAdjL = charIDToTypeID("AdjL");
    desc2.putObject(idUsng, idAdjL, desc3);
    executeAction(idMk, desc2, DialogModes.NO);

    /* create levels layer */
    var idMk = charIDToTypeID("Mk  ");
    var desc13 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref9 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref9.putClass(idAdjL);
    desc13.putReference(idnull, ref9);
    var idUsng = charIDToTypeID("Usng");
    var desc14 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc14.putString(idNm, __ss_ilm_getLowLayerName());
    var idType = charIDToTypeID("Type");
    var desc15 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID("presetKind");
    var idpresetKindType = stringIDToTypeID("presetKindType");
    var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
    desc15.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
    var idLvls = charIDToTypeID("Lvls");
    desc14.putObject(idType, idLvls, desc15);
    var idAdjL = charIDToTypeID("AdjL");
    desc13.putObject(idUsng, idAdjL, desc14);
    executeAction(idMk, desc13, DialogModes.NO);
}

function /* void */ __ss_ilm_action_createFullMask(tabId) {
    /* clear existing selection */
    __ss_ilm_action_selectNone()

    /* create group */
    var idMk = charIDToTypeID("Mk  ");
    var desc6 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref5 = new ActionReference();
    var idlayerSection = stringIDToTypeID("layerSection");
    ref5.putClass(idlayerSection);
    desc6.putReference(idnull, ref5);
    var idUsng = charIDToTypeID("Usng");
    var desc7 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc7.putString(idNm, __ss_ilm_getILMGroupName());
    var idlayerSection = stringIDToTypeID("layerSection");
    desc6.putObject(idUsng, idlayerSection, desc7);
    executeAction(idMk, desc6, DialogModes.NO);

    /* move layer */
    var idmove = charIDToTypeID("move");
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref6 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref6.putEnumerated(idLyr, idOrdn, idTrgt);
    desc8.putReference(idnull, ref6);
    var idT = charIDToTypeID("T   ");
    var ref7 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idFrnt = charIDToTypeID("Frnt");
    ref7.putEnumerated(idLyr, idOrdn, idFrnt);
    desc8.putReference(idT, ref7);
    executeAction(idmove, desc8, DialogModes.NO);

    /* create helper layer */
    __ss_ilm_action_createHelperLayer(tabId)
}

/*
 * This method creates all layers for a zone mask adjustment.
 * It creates a group which contains a BW layer to convert the
 * image to a black and white image and a curves layer for
 * selecting the tonal range.
 */
function /* void */ __ss_ilm_action_createZoneMask(tabId) {
    /* clear existing selection */
    __ss_ilm_action_selectNone()

    /* create group */
    var idMk = charIDToTypeID("Mk  ");
    var desc6 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref5 = new ActionReference();
    var idlayerSection = stringIDToTypeID("layerSection");
    ref5.putClass(idlayerSection);
    desc6.putReference(idnull, ref5);
    var idUsng = charIDToTypeID("Usng");
    var desc7 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc7.putString(idNm, __ss_ilm_getILMGroupName());
    var idlayerSection = stringIDToTypeID("layerSection");
    desc6.putObject(idUsng, idlayerSection, desc7);
    executeAction(idMk, desc6, DialogModes.NO);

    /* move layer */
    var idmove = charIDToTypeID("move");
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref6 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref6.putEnumerated(idLyr, idOrdn, idTrgt);
    desc8.putReference(idnull, ref6);
    var idT = charIDToTypeID("T   ");
    var ref7 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idFrnt = charIDToTypeID("Frnt");
    ref7.putEnumerated(idLyr, idOrdn, idFrnt);
    desc8.putReference(idT, ref7);
    executeAction(idmove, desc8, DialogModes.NO);

    // create helper Layer 
    __ss_ilm_action_createHelperLayer(tabId)

    /* create curves layer */
    var idMk = charIDToTypeID("Mk  ");
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref8 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref8.putClass(idAdjL);
    desc8.putReference(idnull, ref8);
    var idUsng = charIDToTypeID("Usng");
    var desc9 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc9.putString(idNm, __ss_ilm_getZoneLayerName());
    var idType = charIDToTypeID("Type");
    var desc10 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID("presetKind");
    var idpresetKindType = stringIDToTypeID("presetKindType");
    var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
    desc10.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
    var idCrvs = charIDToTypeID("Crvs");
    desc9.putObject(idType, idCrvs, desc10);
    var idAdjL = charIDToTypeID("AdjL");
    desc8.putObject(idUsng, idAdjL, desc9);
    executeAction(idMk, desc8, DialogModes.NO);
}

/*
 * This method sets the curve values fro the zone curves layer.
 */
function /* void */ __ss_ilm_action_setZoneMaskValues( /*[ [int, int] ]*/ values) {
    var idsetd = charIDToTypeID("setd");
    var desc13 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref6 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref6.putEnumerated(idAdjL, idOrdn, idTrgt);
    desc13.putReference(idnull, ref6);
    var idT = charIDToTypeID("T   ");
    var desc14 = new ActionDescriptor();
    var idAdjs = charIDToTypeID("Adjs");
    var list3 = new ActionList();
    var desc15 = new ActionDescriptor();
    var idChnl = charIDToTypeID("Chnl");
    var ref7 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idCmps = charIDToTypeID("Cmps");
    ref7.putEnumerated(idChnl, idChnl, idCmps);
    desc15.putReference(idChnl, ref7);
    var idCrv = charIDToTypeID("Crv ");
    var list4 = new ActionList();

    for (i in values) {
        var pair = values[i]
        var xValue = pair[0]
        var yValue = pair[1]
        var desc17 = new ActionDescriptor();
        var idHrzn = charIDToTypeID("Hrzn");
        desc17.putDouble(idHrzn, xValue);
        var idVrtc = charIDToTypeID("Vrtc");
        desc17.putDouble(idVrtc, yValue);
        var idPnt = charIDToTypeID("Pnt ");
        list4.putObject(idPnt, desc17);
    }

    desc15.putList(idCrv, list4);
    var idCrvA = charIDToTypeID("CrvA");
    list3.putObject(idCrvA, desc15);
    desc14.putList(idAdjs, list3);
    var idCrvs = charIDToTypeID("Crvs");
    desc13.putObject(idT, idCrvs, desc14);
    executeAction(idsetd, desc13, DialogModes.NO);
}

/*
 * This methods deletes the previously created helper group.
 */
function /* void */ __ss_ilm_action_deleteIMLGroup() {
    /* select layer */
    var idslct = charIDToTypeID("slct");
    var desc16 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref10 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    ref10.putName(idLyr, __ss_ilm_getILMGroupName());
    desc16.putReference(idnull, ref10);
    var idMkVs = charIDToTypeID("MkVs");
    desc16.putBoolean(idMkVs, false);
    executeAction(idslct, desc16, DialogModes.NO);
    /* delete group/layer */
    var idDlt = charIDToTypeID("Dlt ");
    var desc17 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref11 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref11.putEnumerated(idLyr, idOrdn, idTrgt);
    desc17.putReference(idnull, ref11);
    executeAction(idDlt, desc17, DialogModes.NO);
}

/*
 * This method creates a selection based on the current image.
 */
function /* void */ __ss_ilm_action_createSelection() {
    var idsetd = charIDToTypeID("setd");
    var desc29 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref23 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idfsel = charIDToTypeID("fsel");
    ref23.putProperty(idChnl, idfsel);
    desc29.putReference(idnull, ref23);
    var idT = charIDToTypeID("T   ");
    var desc30 = new ActionDescriptor();
    var idT = charIDToTypeID("T   ");
    var ref24 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idGry = charIDToTypeID("Gry ");
    ref24.putEnumerated(idChnl, idChnl, idGry);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref24.putEnumerated(idLyr, idOrdn, idMrgd);
    desc30.putReference(idT, ref24);
    var idSrctwo = charIDToTypeID("Src2");
    var ref25 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idGry = charIDToTypeID("Gry ");
    ref25.putEnumerated(idChnl, idChnl, idGry);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref25.putEnumerated(idLyr, idOrdn, idMrgd);
    desc30.putReference(idSrctwo, ref25);
    var idClcl = charIDToTypeID("Clcl");
    desc29.putObject(idT, idClcl, desc30);
    executeAction(idsetd, desc29, DialogModes.NO);
}

/*
 * This method creates a channel mask based in the current image.
 */
function /* void */ __ss_ilm_action_createChannel( /*String*/ name) {
    /* create channel */
    var idMk = charIDToTypeID("Mk  ");
    var desc97 = new ActionDescriptor();
    var idNw = charIDToTypeID("Nw  ");
    var desc98 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc98.putString(idNm, name);
    var idClrI = charIDToTypeID("ClrI");
    var idMskI = charIDToTypeID("MskI");
    var idMskA = charIDToTypeID("MskA");
    desc98.putEnumerated(idClrI, idMskI, idMskA);
    var idClr = charIDToTypeID("Clr ");
    var desc99 = new ActionDescriptor();
    var idRd = charIDToTypeID("Rd  ");
    desc99.putDouble(idRd, 255.000000);
    var idGrn = charIDToTypeID("Grn ");
    desc99.putDouble(idGrn, 0.000000);
    var idBl = charIDToTypeID("Bl  ");
    desc99.putDouble(idBl, 0.000000);
    var idRGBC = charIDToTypeID("RGBC");
    desc98.putObject(idClr, idRGBC, desc99);
    var idOpct = charIDToTypeID("Opct");
    desc98.putInteger(idOpct, 50);
    var idChnl = charIDToTypeID("Chnl");
    desc97.putObject(idNw, idChnl, desc98);
    executeAction(idMk, desc97, DialogModes.NO);

    /* select channel */
    var idslct = charIDToTypeID("slct");
    var desc106 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref85 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    ref85.putName(idChnl, name);
    desc106.putReference(idnull, ref85);
    executeAction(idslct, desc106, DialogModes.NO);

    /* apply image to channel */
    var idAppI = charIDToTypeID("AppI");
    var desc103 = new ActionDescriptor();
    var idWith = charIDToTypeID("With");
    var desc104 = new ActionDescriptor();
    var idT = charIDToTypeID("T   ");
    var ref83 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idRGB = charIDToTypeID("RGB ");
    ref83.putEnumerated(idChnl, idChnl, idRGB);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref83.putEnumerated(idLyr, idOrdn, idMrgd);
    desc104.putReference(idT, ref83);
    var idPrsT = charIDToTypeID("PrsT");
    desc104.putBoolean(idPrsT, true);
    var idClcl = charIDToTypeID("Clcl");
    desc103.putObject(idWith, idClcl, desc104);
    executeAction(idAppI, desc103, DialogModes.NO);
}

/*
 * This function moves the currently selected layer onto the top of the layer stack.
 */
function /* void */ __ss_ilm_action_moveLayerFront() {
    var idmove = charIDToTypeID("move");
    var desc14 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref12 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref12.putEnumerated(idLyr, idOrdn, idTrgt);
    desc14.putReference(idnull, ref12);
    var idT = charIDToTypeID("T   ");
    var ref13 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idFrnt = charIDToTypeID("Frnt");
    ref13.putEnumerated(idLyr, idOrdn, idFrnt);
    desc14.putReference(idT, ref13);
    executeAction(idmove, desc14, DialogModes.NO);
}

/*
 * This method applies the current image as layer mask to 
 * the currently selected layer.
 */
function /* void */ __ss_ilm_action_applyLayerMask() {
    var idAppI = charIDToTypeID("AppI");
    var desc11 = new ActionDescriptor();
    var idWith = charIDToTypeID("With");
    var desc12 = new ActionDescriptor();
    var idT = charIDToTypeID("T   ");
    var ref9 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idChnl = charIDToTypeID("Chnl");
    var idRGB = charIDToTypeID("RGB ");
    ref9.putEnumerated(idChnl, idChnl, idRGB);
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idMrgd = charIDToTypeID("Mrgd");
    ref9.putEnumerated(idLyr, idOrdn, idMrgd);
    desc12.putReference(idT, ref9);
    var idPrsT = charIDToTypeID("PrsT");
    desc12.putBoolean(idPrsT, true);
    var idClcl = charIDToTypeID("Clcl");
    desc11.putObject(idWith, idClcl, desc12);
    executeAction(idAppI, desc11, DialogModes.NO);
}

/*
 * This methods creates a new curve layer with the given name.
 */
function /* void */ __ss_ilm_action_createCurvesLayer( /* String */ name) {
    var idMk = charIDToTypeID("Mk  ");
    var desc8 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref8 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref8.putClass(idAdjL);
    desc8.putReference(idnull, ref8);
    var idUsng = charIDToTypeID("Usng");
    var desc9 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc9.putString(idNm, name);
    var idType = charIDToTypeID("Type");
    var desc10 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID("presetKind");
    var idpresetKindType = stringIDToTypeID("presetKindType");
    var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
    desc10.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
    var idCrvs = charIDToTypeID("Crvs");
    desc9.putObject(idType, idCrvs, desc10);
    var idAdjL = charIDToTypeID("AdjL");
    desc8.putObject(idUsng, idAdjL, desc9);
    executeAction(idMk, desc8, DialogModes.NO);

    __ss_ilm_action_applyLayerMask()
    __ss_ilm_action_moveLayerFront()
}

/*
 * This method creates a levels layer with the given name.
 */
function /* void */ __ss_ilm_action_createLevelsLayer(name) {
    var idMk = charIDToTypeID("Mk  ");
    var desc21 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref19 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref19.putClass(idAdjL);
    desc21.putReference(idnull, ref19);
    var idUsng = charIDToTypeID("Usng");
    var desc22 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc22.putString(idNm, name);
    var idType = charIDToTypeID("Type");
    var desc23 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID("presetKind");
    var idpresetKindType = stringIDToTypeID("presetKindType");
    var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
    desc23.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
    var idLvls = charIDToTypeID("Lvls");
    desc22.putObject(idType, idLvls, desc23);
    var idAdjL = charIDToTypeID("AdjL");
    desc21.putObject(idUsng, idAdjL, desc22);
    executeAction(idMk, desc21, DialogModes.NO);

    __ss_ilm_action_applyLayerMask()
    __ss_ilm_action_moveLayerFront()
}

/*
 * This method creates a Hue/Stauration layer with the given name.
 */
function /* void */ __ss_ilm_action_createHueSaturationLayer(name) {
    var idMk = charIDToTypeID("Mk  ");
    var desc24 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref20 = new ActionReference();
    var idAdjL = charIDToTypeID("AdjL");
    ref20.putClass(idAdjL);
    desc24.putReference(idnull, ref20);
    var idUsng = charIDToTypeID("Usng");
    var desc25 = new ActionDescriptor();
    var idNm = charIDToTypeID("Nm  ");
    desc25.putString(idNm, name);
    var idType = charIDToTypeID("Type");
    var desc26 = new ActionDescriptor();
    var idpresetKind = stringIDToTypeID("presetKind");
    var idpresetKindType = stringIDToTypeID("presetKindType");
    var idpresetKindDefault = stringIDToTypeID("presetKindDefault");
    desc26.putEnumerated(idpresetKind, idpresetKindType, idpresetKindDefault);
    var idClrz = charIDToTypeID("Clrz");
    desc26.putBoolean(idClrz, false);
    var idHStr = charIDToTypeID("HStr");
    desc25.putObject(idType, idHStr, desc26);
    var idAdjL = charIDToTypeID("AdjL");
    desc24.putObject(idUsng, idAdjL, desc25);
    executeAction(idMk, desc24, DialogModes.NO);

    __ss_ilm_action_applyLayerMask()
    __ss_ilm_action_moveLayerFront()
}

/*@UNUSED ??? */
function /* void */ __ss_ilm_action_selectLayer(name) {
    var idslct = charIDToTypeID("slct");
    var desc167 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref136 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    ref136.putName(idLyr, name);
    desc167.putReference(idnull, ref136);
    var idMkVs = charIDToTypeID("MkVs");
    desc167.putBoolean(idMkVs, false);
    executeAction(idslct, desc167, DialogModes.NO);
}

/*
 * This method deselects the current selection. This method is
 * called before we create layers because the current selection
 * would be used for creating the layer's layer mask.
 */
function /* void */ __ss_ilm_action_selectNone() {
    var idsetd = charIDToTypeID("setd");
    var desc45 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref4 = new ActionReference();
    var idChnl = charIDToTypeID("Chnl");
    var idfsel = charIDToTypeID("fsel");
    ref4.putProperty(idChnl, idfsel);
    desc45.putReference(idnull, ref4);
    var idT = charIDToTypeID("T   ");
    var idOrdn = charIDToTypeID("Ordn");
    var idNone = charIDToTypeID("None");
    desc45.putEnumerated(idT, idOrdn, idNone);
    executeAction(idsetd, desc45, DialogModes.NO);
}


/****************************************************************************/
/*                         HELPER METHODS (internal)                        */
/****************************************************************************/

/*
 *   returns the group layer name
 */
function /*String*/ __ss_ilm_getILMGroupName() {
    return "__ss_ilm_group"
}

/*
 *    returns the layer name of the highligh levels
 */
function /*String*/ __ss_ilm_getHighLayerName() {
    return "__ss_ilm_high"
}

/*
 *   returns the layer name of the midtone levels
 */
function /*String*/ __ss_ilm_getMidLayerName() {
    return "__ss_ilm_mid"
}

/*
 *   returns the layer name of the Low levels
 */
function /*String*/ __ss_ilm_getLowLayerName() {
    return "__ss_ilm_low"
}

function /*String*/ __ss_ilm_getZoneLayerName() {
    return "__ss_ilm_zone"
}

/*
 * Checks whether we have an document opened or not.
 */
function /*boolean*/ __ss_ilm_haveDocument() {
    if (activeDocument !== undefined) {
        return true;
    } else {
        return false;
    }
}

/*
 *   Assumes that the currently active layer is a level adjustment layer.
 */
function /* void */ __ss_ilm_setLevelAdj(inBlack, inWhite, gamma, outBlack, outWhite) {
    var d, d1, d2, l, l1, l2, r, r1, s2t;
    if (outBlack === null) {
        outBlack = 0;
    }
    if (outWhite === null) {
        outWhite = 255;
    }
    s2t = function (s) {
        return app.stringIDToTypeID(s);
    };
    d = new ActionDescriptor();
    r = new ActionReference();
    r.putEnumerated(s2t('adjustmentLayer'), s2t('ordinal'), s2t('targetEnum'));
    d.putReference(s2t('target'), r);
    d1 = new ActionDescriptor();
    d1.putEnumerated(s2t('presetKind'), s2t('presetKindType'), s2t('presetKindCustom'));
    l = new ActionList();
    d2 = new ActionDescriptor();
    r1 = new ActionReference();
    r1.putEnumerated(s2t('channel'), s2t('channel'), s2t('composite'));
    d2.putReference(s2t('channel'), r1);
    l1 = new ActionList();
    l1.putInteger(inBlack);
    l1.putInteger(inWhite);
    d2.putList(s2t('input'), l1);
    d2.putDouble(s2t('gamma'), gamma);
    l2 = new ActionList();
    l2.putInteger(outBlack);
    l2.putInteger(outWhite);
    d2.putList(s2t('output'), l2);
    l.putObject(s2t('levelsAdjustment'), d2);
    d1.putList(s2t('adjustment'), l);
    d.putObject(s2t('to'), s2t('levels'), d1);
    return executeAction(s2t('set'), d, DialogModes.NO);
}

/*
 * Find the specified layer inside the specified group and return it
 * or undefined if the layer does not exists.
 */
function /*ArtLayer*/ __ss_ilm_findLayer(groupName, layerName) {
    var layer

    if (activeDocument) {
        layer = activeDocument.layerSets.getByName(groupName).artLayers.getByName(layerName)
    }

    return layer
}

/*
 * This method returns the layer descriptor for the currently selected layer.
 */
function /* ActionDecriptor */ __ss_ilm_getLayerDescriptor() {
    var ref = new ActionReference();
    ref.putEnumerated(charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt"));
    return executeActionGet(ref);
}

/*
 * This method reads 2 bytes from the raw data at the given offset and
 * converts them to a short integer.
 */
function /* short */ __ss_ilm_readRawShort(raw, offset) {
    var high = raw.charCodeAt(offset)
    var low = raw.charCodeAt(offset + 1)
    var shortValue = (high << 8) + low;
    if (shortValue > 0x7FFF) {
        shortValue = 0xFFFF0000 ^ shortValue;
    }
    return shortValue
}

/*
 * Reads and returns the Low input value for the current layer.
 */
function /* short */ __ss_ilm_getLevelLayerInputLow() {
    var desc = __ss_ilm_getLayerDescriptor()
    var adjList = desc.getList(charIDToTypeID('Adjs'))
    var adjDesc = adjList.getObjectValue(0)
    var raw = adjDesc.getData(stringIDToTypeID('legacyContentData'))
        /*
         * we need to read the value from the raw format:
         * http://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
         */
    return __ss_ilm_readRawShort(raw, 2);
}

/*
 * This function computes the curves layer points for the given gaussian function. 
 * The value indicates the peak/center to the caussian curve and the width specifies
 * the width of the curve.
 */
function /* [ [int, int] ] */ __ss_ilm_getGaussianCurve(value, width) {
    var gaussian = function (x, a, b, c) {
        var expValue = -1 * ((x - b) * (x - b)) / ((2 * c) * (2 * c))
        return a * Math.exp(expValue)
    }
    var stepCount = 50
    var stepSize = Math.round(256 / stepCount)
    var left = []
    var right = []

    do {
        stepCount = stepCount - 5
        stepSize = Math.round(256 / stepCount)
        left = []
        right = []

        // compute right part
        for (i = 1; i < stepCount - 1; i++) {
            var currentStep = value + stepSize * i
            var gaussianValue = gaussian(currentStep, 255, value, width)
            if (gaussianValue > 1 && currentStep < 255) {
                right.push([currentStep, gaussianValue])
            } else {
                if (currentStep > 255) {
                    gaussianValue = gaussian(255, 255, value, width)
                }
                right.push([255, gaussianValue])
                break
            }
        }
        // only right values    
        for (i = 0; i < stepCount - 1; i++) {
            var currentStep = value - stepSize * i
            var gaussianValue = gaussian(currentStep, 255, value, width)
            if (gaussianValue > 1 && currentStep > 0) {
                left.push([currentStep, gaussianValue])
            } else {
                if (currentStep < 0) {
                    gaussianValue = gaussian(0, 255, value, width)
                }
                left.push([0, gaussianValue])
                break
            }
        }
        left.reverse()
            // photoshop only allows us to set 14 points on the curve
    } while (left.concat(right).length > 14)

    return left.concat(right)
}


/****************************************************************************/
/*                             PUBLIC API                                   */
/****************************************************************************/

/*
 * Shows a dialog box with the given message. Using alert from inside
 * Photoshop look mor like a normal dialog versus a JS error message
 * when used from the panel code.
 */
function /* void */ __ss_ilm_showMessage(msg) {
    alert(msg)
}

function /* String */ __ss_ilm_showPrompt(msg, value) {
    var result = prompt(msg, value)

    /* convert invalid string to empty string because null would be stringified by CSInterface */
    if (!result) {
        return ""
    }

    return result
}

/*
 * Set the value of the IML high layer to the specified value.
 */
function /* void */ __ss_ilm_setHighValue(value) {
    var /*String*/ groupName = __ss_ilm_getILMGroupName()
    var /*String*/ layerName = __ss_ilm_getHighLayerName()
    var /*ArtLayer*/ levelsLayer = __ss_ilm_findLayer(groupName, layerName)

    if (levelsLayer !== undefined) {
        app.activeDocument.activeLayer = levelsLayer
        var LowValue = 200 - (2 * value)
        __ss_ilm_setLevelAdj(LowValue, 255, 1, 0, 255)
    } else {
        __ss_ilm_showMessage("Cannot find high Layer")
    }
}

/*
 * Set the value of the IML mid  layer to the specified value.
 */
function /* void */ __ss_ilm_setMidValue(value) {
    var /*String*/ groupName = __ss_ilm_getILMGroupName()
    var /*String*/ layerName = __ss_ilm_getMidLayerName()
    var /*ArtLayer*/ levelsLayer = __ss_ilm_findLayer(groupName, layerName)

    if (levelsLayer !== undefined) {
        app.activeDocument.activeLayer = levelsLayer
        var LowValue = 200 - (2 * value)
        __ss_ilm_setLevelAdj(LowValue, 255, 1, 0, 255)
    } else {
        __ss_ilm_showMessage("Cannot find highlightLayer")
    }
}

/*
 * Set the value of the IML Low layer to the specified value.
 */
function /* void */ __ss_ilm_setLowValue(value) {
    var /*String*/ groupName = __ss_ilm_getILMGroupName()
    var /*String*/ layerName = __ss_ilm_getLowLayerName()
    var /*ArtLayer*/ levelsLayer = __ss_ilm_findLayer(groupName, layerName)

    if (levelsLayer !== undefined) {
        app.activeDocument.activeLayer = levelsLayer
        var LowValue = 200 - (2 * value)
        __ss_ilm_setLevelAdj(LowValue, 255, 1, 0, 255)
    } else {
        __ss_ilm_showMessage("Cannot find low Layer")
    }
}

/*
 * This method updates the zone curve layer for the given values.
 */
function /* void */ __ss_ilm_setZoneValue(value, width) {
    var /*String*/ groupName = __ss_ilm_getILMGroupName()
    var /*String*/ layerName = __ss_ilm_getZoneLayerName()
    var /*ArtLayer*/ curveLayer = __ss_ilm_findLayer(groupName, layerName)

    if (curveLayer !== undefined) {
        app.activeDocument.activeLayer = curveLayer
        var value256 = value * 2.56

        var curveValues = __ss_ilm_getGaussianCurve(value256, width)
        __ss_ilm_action_setZoneMaskValues(curveValues)
    } else {
        __ss_ilm_showMessage("Cannot find curve layer")
    }
}

/*
 * Shows the color picker and have the user select a color.
 */
function /* Color */ __ss_ilm_userColorSelector() {
    var foregroundColorSaved = app.foregroundColor
    var result = app.showColorPicker()
    if (result) {
        var selectedColor = app.foregroundColor
        app.foregroundColor = foregroundColorSaved
        return selectedColor
    } else {
        return undefined
    }
}

/*
 * This method asks the user to select a color from the picture 
 * and the sets the zones layer to the luminosity of the selected
 * color.
 */
function /* String<Int> */ __ss_ilm_selectZoneFromUserColor(tabId, width) {
    // hide our group
    var psVersion = app.version.split("\.")
    var luminosity = undefined
    var value = undefined
    var groupName = __ss_ilm_getILMGroupName()
    var zoneName = __ss_ilm_getZoneLayerName()
    var groupLayer = activeDocument.layerSets.getByName(groupName)
    var zoneLayer = __ss_ilm_findLayer(groupName, zoneName)
    activeDocument.activeLayer = groupLayer
    groupLayer.visible = false

    // have user select color 
    var color = __ss_ilm_userColorSelector()

    // extract luminosity and sety
    if (color) {
        var minValue = Math.min(color.rgb.red, color.rgb.green, color.rgb.blue)
        var maxValue = Math.max(color.rgb.red, color.rgb.green, color.rgb.blue)
        if (TAB_ID.LUMINOSITY_MASKS == tabId) {
            if ( psVersion[0] > 14 ) {
                luminosity = maxValue;
            } else {
                luminosity = Math.round(0.2126 * color.rgb.red + 0.7152 * color.rgb.green + 0.0722 * color.rgb.blue)
            }
            value = Math.round(luminosity /2.56)
            __ss_ilm_setZoneValue(value, width)
        } else if (TAB_ID.SATURATION_MASKS == tabId) {
            var saturation = (maxValue > 0) ? (maxValue - minValue) / maxValue : 0
            value = Math.round(saturation * 100);
            __ss_ilm_setZoneValue(value, width)
        }
    }

    // show our group again
    groupLayer.visible = true
    activeDocument.activeLayer = zoneLayer

    return value
}

function /* void */ __ss_ilm_openURL(url) {
    try {
        var URL = new File(Folder.temp + "/ILM.html");
        URL.open("w");
        URL.writeln('<html><HEAD><meta HTTP-EQUIV="REFRESH" content="0; url=' + url + '"></HEAD></HTML>');
        URL.close();
        URL.execute(); //  The temp file is created but this fails to open the users default browser using Photoshop CC prior Photoshop versions work  
    } catch (e) {
        alert("Error, Can Not Open.");
    };
}

function /* boolean */ __ss_ilm_fileExists(filename) {
    var file = new File(filename)
    return file.exists
}