//If script doesn't work – check if you installed ImageMagick properly and fix path below 
//!IMPORTANT provide path to FOLDER (not to Convert tool itself)

var CONVERT_PATH_FOR_OSX = "/opt/ImageMagick/bin";
var CONVERT_PATH_FOR_WIN = 'C:\\ImageMagick'; 


// Edit -> templates -> output modules. 
//Create module with name GifMagick, format PNG Sequence and Channels RGB+Alpha
var PNG_SEQUENCE_TEMPLATE = "Gif";
/*
=============================================================================
=============================================================================
=============================================================================
=============================================================================
*/
//Constants
var SCRIPT_NAME = "[GifMagick]";
var NAME = "GifMagick"
var SELECT_COMPOSITION = "Select composition first";
var UNDO_GROUP = "Create gif within timerange";
var SAVE_DIALOG = "Provide name for resulting gif file";
var DONE_MESSAGE = "Done. Check your gif there: ";
var NEED_FILE = "Sorry, " + NAME + " needs a name for your file";
var CANT_DELETE = "Could't clear directory. Action is not allowed";
var NO_CONVERT = "Check if you installed ImageMagick properly \nYou could provide valid path to Convert tool at the top of the script. Don't forget relaunch " + NAME;
var DISCLAMER_TEXT = 'Place markers on timeline';
var DISCLAIMER_TEXT2 = 'to select gif interval';
var GIF_WIDTH_TEXT = "Width";
var GIF_HEIGHT_TEXT = "Height";
var GIF_LOOP_TEXT = "Loop";
var GIF_OPTIMIZE_TEXT = "Optimize";
var GIF_ALPHA_TEXT = "Alpha channel"
var GIF_FPS_TEXT = "FPS";
var GIF_SPEED_TEXT = "Speed";
var CREATE_GIF_TEXT = 'Export gif';
var ALLOW_CREATE_FILES = 'Allow ' + NAME + ' to create gif files \nGo to Preferences -> General -> Allow scripts to Write Files and Access Network';
var CREATE_TEMPLATE_FIRST = "Create template for PNG Sequence (RGB+Alpha) with name '" + PNG_SEQUENCE_TEMPLATE + "'\nEdit -> Templates -> OutputModule";
var CLEAN_QUEUE = "Problem with render queue. Try to clean it";
var TMP_FOLDER_NAME = 'shots_by_gifmagick';
//Globals
try {
    var ActiveItem = app.project.activeItem;
    var Optimize = 0;
    var Looped = 1;
    var Alpha = 0;
    var FPS = Math.round(ActiveItem.frameRate, 2);
    var Speed = 1;
    var Resolution = [Math.min(600, ActiveItem.width), Math.round(ActiveItem.height / Math.max(ActiveItem.width / 600, 1))];
    createPalete(this);
} catch (e) {
    alert(e)
    alert(SELECT_COMPOSITION, SCRIPT_NAME);
}

//Helpers
function osIsWin() {
    if ($.os.indexOf("Win") != -1) {
        return true;
    } else {
        return false;
    }
}
//TODO CONVERT FOR WINDOWS
function getConvertPath() {
    if (osIsWin()) {
        return CONVERT_PATH_FOR_WIN;
    } else {
        return CONVERT_PATH_FOR_OSX;
    }
}

function getGifPath(gifFile) {
    return gifFile;
}

function getPngPath(gifFile) {
    if (osIsWin()) {
        return gifFile + '\\' + TMP_FOLDER_NAME;
    } else {
        return gifFile + '/' + TMP_FOLDER_NAME;
    }
}

function getConvert() {
    if (osIsWin()) {
        if (getConvertPath() == undefined) {
            return 'convert'
        } else {
            return getConvertPath() + '\\convert';
        }
    } else {
        return getConvertPath() + '/convert';
    }

}

function getPngTemplate(path) {
    if (osIsWin()) {
        return path + "\\[compName]_[######].png";
    } else {
        return path + "/[compName]_[######].png";
    }

}

function getPngFiles(pngPath) {
    if (osIsWin()) {
        return pngPath + "\\*.png"
    } else {
        return pngPath + "/*.png"
    }
}

function getFps() {
    return FPS;
}

function getSpeed() {
    return 5 + 'x' + 120 * Speed * (FPS / ActiveItem.frameRate);
}

function getLoop() {
    return Looped;
}

function getOptimize() {
    return Optimize;
}

function getAlpha() {
    return Alpha;
}

function getResolution() {
    return Resolution;
}

function getTimeRangeString() {
    timeRange = getTimeRange(ActiveItem);
    return "from " + timeRange[0] + " to" + timeRange[1];
}

//MAIN BODY
function getTimeRange(composition) {
    var timeRange = [0, composition.duration];
    var tempNull = composition.layers.addNull(composition.duration);
    var tempPos = tempNull.property("ADBE Transform Group").property("ADBE Position");
    tempPos.expression = "x = thisComp.marker.numKeys;[x,0];";
    var result = tempPos.value[0];
    //alert("There are " + result + " comp markers");
    for (x = 1; x <= Math.min(result, 2); x++) {
        tempPos.expression = "x = thisComp.marker.key(" + x + ").time;[x,0];";
        //alert("Marker " + x + " time = " + tempPos.value[0]);
        timeRange[x - 1] = tempPos.value[0];
    }
    tempNull.remove();
    return timeRange;
}

function main(win) {
    if (ActiveItem == null || !(ActiveItem instanceof CompItem)) { //[or CompItem] if not selected – fireup error message
        alert(SELECT_COMPOSITION, SCRIPT_NAME);
    } else {
        try {
            if (
                (!osIsWin() && (makeApiCall(getConvert() + ' -version').search(/license/ig) !== -1)) ||
                (osIsWin() && (makeApiCall(getConvert() + ' -version').length < 5))
                ) {          
                var gifFile = File.saveDialog(SAVE_DIALOG, preset = '.gif'); //asking for gif path      
                if (gifFile) {
                    var pngPath = getPngPath(gifFile.parent.fsName);
                    var pngFiles = getPngFiles(pngPath);                   
                    createFolder(pngPath);
                    timeRange = getTimeRange(ActiveItem);
                    prevFrameRate = ActiveItem.frameRate;
                    ActiveItem.frameRate = getFps();
                    var duration = timeRange[1] - timeRange[0];
                    currentItem = 1;
                    win.makeGif.text = 'Rendering...';
                    app.project.renderQueue.items.add(ActiveItem);
                    app.project.renderQueue.item(currentItem).timeSpanStart = timeRange[0];
                    app.project.renderQueue.item(currentItem).timeSpanDuration = duration;
                    OutputMO = app.project.renderQueue.item(currentItem).outputModule(1);
                    try {
                        OutputMO.applyTemplate(PNG_SEQUENCE_TEMPLATE);
                        OutputMO.file = new File(getPngTemplate(pngPath));
                        try {
                            app.project.renderQueue.render();
                            app.project.renderQueue.item(currentItem).remove();
                            ActiveItem.frameRate = prevFrameRate; //restore frame rate
                            win.makeGif.text = 'Cooking gif...';                        
                            makeGif(pngFiles, pngPath.slice(0, -TMP_FOLDER_NAME.length) + gifFile.name);
                            deleteFolder(pngPath);
                            win.makeGif.text = 'Done!';
                            $.sleep(700);
                            win.makeGif.text = CREATE_GIF_TEXT;                            
                        } catch(e) {
                            alert(NO_CONVERT, SCRIPT_NAME);
                            deleteFolder(pngPath);
                            ActiveItem.frameRate = prevFrameRate; //restore frame rate
                            win.makeGif.text = CREATE_GIF_TEXT;
                        }
                    } catch (e) {
                        alert(CREATE_TEMPLATE_FIRST, SCRIPT_NAME);
                        app.project.renderQueue.item(currentItem).remove();
                        deleteFolder(pngPath);
                        ActiveItem.frameRate = prevFrameRate; //restore frame rate
                        win.makeGif.text = CREATE_GIF_TEXT;
                    }

                }
            } else {
                alert(NO_CONVERT, SCRIPT_NAME);
            }
        } catch (e) {
            alert(ALLOW_CREATE_FILES, SCRIPT_NAME);
        }
    }
}


function buildApiCall(pngFiles, gifFile) {
    var speedOption = "-delay " + getSpeed(); //2 -> 2x, 0.5 -> 0.5x
    var loopOption = "-loop " + (getLoop() == 1 ? '0' : '1'); // 0 -> loop forever
    //var optimizeColors = "-dither None -colors 255";
    var resize = '-resize "' + getResolution()[0] + 'x' + getResolution()[1] + '^" -gravity center -crop ' + getResolution()[0] + 'x' + getResolution()[1] + '+0+0 +repage';
    var optimizeLayers = '-fuzz "80%" -layers OptimizeFrame';
    var gifCmd = getConvert();
    gifCmd += ' ' + loopOption;
    gifCmd += ' ' + speedOption;
    //gifCmd += getOptimize() ? ' ' + optimizeColors : '';
    gifCmd += getAlpha() == 1 ? ' -alpha set -dispose previous' : '';
    gifCmd += ' "' + pngFiles + '"';
    gifCmd += ' ' + resize;
    gifCmd += getOptimize() ? ' ' + "-dither none -matte -depth 8 -deconstruct -layers optimize"  
 : '';
    if (osIsWin()) {
        gifCmd += ' "' + gifFile + '"';
    } else {
        gifCmd += ' ' + gifFile + '.gif';
    }
    // alert(gifCmd);
    return gifCmd;
}

function makeGif(pngFiles, gifFile) {
    var cmd = buildApiCall(pngFiles, gifFile);
    //alert(cmd);
    try {
        makeApiCall(cmd);
    } catch (e) {
        alert(NO_CONVERT, SCRIPT_NAME)
    }
}

function makeApiCall(cmd) {
    if (osIsWin()) {
        return system.callSystem("cmd /c \"" + cmd + "\"");
    } else {
        return system.callSystem(cmd);
    }
}

function deleteFolder(path) {

    if (osIsWin()) {
        var cmd = "rmdir /s /q " + path;
        system.callSystem("cmd /c \"" + cmd + "\"");
    } else {
        var cmd = "rm -rf " + path;
        system.callSystem(cmd);
    }
}

function createFolder(path) {
    if (osIsWin()) {
        var cmd = "mkdir " + path;
        system.callSystem("cmd /c \"" + cmd + "\"");
    } else {
        var cmd = "mkdir " + path;
        system.callSystem(cmd);
    }
}

//UI
function createPalete(thisObj) {
    var win = (thisObj instanceof Panel) ? thisObj : new Window('palette', NAME, undefined); {
        win.alignChildren = "fill";
        win.spacing = 0;
        win.centreDisclaimer = win.add('statictext', undefined, DISCLAMER_TEXT);
        win.centreDisclaimer = win.add('statictext', undefined, DISCLAIMER_TEXT2);
        win.centreDisclaimer.align = 'center';
        win.centreDisclaimer = win.add('statictext', undefined, '');
        win.widthLabel = win.add('statictext', undefined, GIF_WIDTH_TEXT);
        win.widthValue = win.add('edittext', undefined, Resolution[0]);
        win.widthValue.onChange = function() {
            Resolution[0] = this.text;
        }

        win.heightLabel = win.add('statictext', undefined, GIF_HEIGHT_TEXT);
        win.heightValue = win.add('edittext', undefined, Resolution[1]);
        win.heightValue.onChange = function() {
            Resolution[1] = this.text;
        }



        win.FPSLabel = win.add('statictext', undefined, GIF_FPS_TEXT);
        win.FPSValue = win.add('edittext', undefined, FPS);
        win.FPSValue.onChange = function() {
            FPS = this.text;
        }
        win.speedLabel = win.add('statictext', undefined, GIF_SPEED_TEXT);

        win.SpeedValue = win.add('edittext', undefined, Speed * 100 + '%')
        win.SpeedValue.onChange = function() {
            if (this.text.slice(-1, ) == '%') {
                Speed = this.text.slice(0, -1) / 100;

            } else {
                Speed = this.text / 100;
            }
            //alert(Speed);

        }
        win.centreDisclaimer = win.add('statictext', undefined, '');
               win.optimizeOption = win.add('checkbox', undefined, GIF_OPTIMIZE_TEXT);
       win.optimizeOption.value = false;
       win.optimizeOption.onClick = function() {
          Optimize = this.value;
      } 
        win.loopOption = win.add('checkbox', undefined, GIF_LOOP_TEXT);
        win.loopOption.value = true;
        win.loopOption.onClick = function() {
            Looped = this.value;
        }

        win.alphaOption = win.add('checkbox', undefined, GIF_ALPHA_TEXT);
        win.alphaOption.value = false;
        win.alphaOption.onClick = function() {
            Alpha = this.value;
        }
        win.centreDisclaimer = win.add('statictext', undefined, '');


        win.makeGif = win.add('button', undefined, CREATE_GIF_TEXT);

        win.makeGif.onClick = function() {
            main(win);
        }


    }

    if (win instanceof Window) {
        win.show();
    } else {
        win.layout.layout(true);
    }
}
//RUN

//main();

//UI
//EXCEPTIONS
//WHERE CONVERT
//SPEED IN PERCENT
//PNG ALPHA
//ERROR MESSAGE -> GIVE ACCESS TO FILE SYSTEM / CHECK CONVERT / ALPHA SEQUENCE / ETC
//CC WIN MAC TESTERS
