/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * ___________________
 *
 *  Copyright 2024 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/

/*global $, Folder, app, File, COLOR, GradientType, GradientColor */

var GRADIENT = {};

GRADIENT.isGradientSameName = function(name) {
    try {
        app.activeDocument.gradients.getByName(name);
        return true;
    } catch (ex) {
        return false;
    }
};
/**
 * Converts a gradient color to data representation.
 * @param {Object} gradientColor - The gradient color object.
 * @param {Object} [pathItem] - The path item (optional).
 * @returns {Array|null} - The gradient data representation or null if invalid.
 */
GRADIENT.gradientColorToData = function (gradientColor, pathItem) {
    // Ensure the gradientColor is valid
    if (!gradientColor || gradientColor.typename !== 'GradientColor' || !gradientColor.gradient) {
        return null;
    }

    var gradient = gradientColor.gradient;

    // Check if the gradient is of a supported type
    if (!gradient || (gradient.type !== GradientType.LINEAR && gradient.type !== GradientType.RADIAL)) {
        return null;
    }

    var stops = [];
    var opacities = [];
    
    // Process gradient stops
    for (var i = 0; i < gradient.gradientStops.length; i++) {
        var stop = gradient.gradientStops[i];
        stops.push({
            midpoint: stop.midPoint ? (stop.midPoint / 100.0) : 0.5, // Default to 0.5
            offset: stop.rampPoint / 100.0,
            color: COLOR.solidColorToData(stop.color)
        });
        opacities.push({
            opacity: opacityCalc = (stop.opacity === 0) ? 0 : (stop.opacity > 0 ? stop.opacity / 100.0 : 1.0),
            midpoint: stop.midPoint ? (stop.midPoint / 100.0) : 0.5,  // Default to 0.5
            offset: stop.rampPoint / 100.0
        });
    }

    var centerPoint = { x: 0.5, y: 0.5 };

    // If pathItem exists, calculate centerPoint based on geometricBounds
    if (pathItem && pathItem.geometricBounds && gradientColor.origin && gradientColor.origin.length) {
        centerPoint.x = (gradientColor.origin[0] - pathItem.geometricBounds[0]) / (pathItem.geometricBounds[2] - pathItem.geometricBounds[0]);
        centerPoint.y = (gradientColor.origin[1] - pathItem.geometricBounds[1]) / (pathItem.geometricBounds[3] - pathItem.geometricBounds[1]);
    }

    var scale = 1.0;
    var aspectRatio = 1.0;
    if (gradient.type === GradientType.RADIAL && pathItem && pathItem.geometricBounds) {
        scale = (gradientColor.length * 2) / (pathItem.geometricBounds[2] - pathItem.geometricBounds[0]);
        aspectRatio = gradientColor.matrix.mValueD;
    }

    return [{
        type: gradient.type === GradientType.RADIAL ? 'radial' : 'linear',
        stops: stops,
        opacities: opacities,
        angle: gradientColor.angle || 0,
        centerPoint: centerPoint,
        scale: scale,
        aspectRatio: aspectRatio,
        hiliteLength: gradientColor.hiliteLength || 0,
        hiliteAngle: gradientColor.hiliteAngle || 0
    }];
};

/**
 * Creates a new gradient from the given data and adds it to the document's gradients.
 * @param {Object} data - The gradient data.
 * @returns {Object} - The new gradient object.
 */
GRADIENT._createGradient = function (data) {
    if (!data.stops || data.stops.length < 2) {
        return alert("Gradient is corrupt and can't be used!");
    }

    var gradientType = data.type === 'linear' ? GradientType.LINEAR : GradientType.RADIAL;

    try {
        return app.activeDocument.gradients.getByName(data.name);
    } catch (ex) {
        // Gradient with the same name does not exist, create a new one.
    }

    var newGradient = app.activeDocument.gradients.add();
    newGradient.name = data.name;
    newGradient.type = gradientType;
    newGradient.angle = data.angle;
    newGradient.hiliteLength = data.hiliteLength || 0;
    newGradient.hiliteAngle = data.hiliteAngle || 0;
    var scaleX = (data.scale || 1.0) * 100.0;
    var scaleY = scaleX * (data.aspectRatio || 1.0);
    var matrix = app.getScaleMatrix(scaleX, scaleY);
    newGradient.matrix = matrix;

    for (var index = 0; index < data.stops.length; index++) {
        if (index > 1) {
            newGradient.gradientStops.add();
        }
        var gradientStop = newGradient.gradientStops[index];
        var stop = data.stops[index];

        gradientStop.midPoint = stop.midpoint * 100.0;
        gradientStop.rampPoint = stop.offset * 100.0;
        gradientStop.color = COLOR.dataToSolidColor(stop.color);
        if (data.opacities && index < data.opacities.length) {
            gradientStop.opacity = data.opacities[index].opacity * 100.0;
        }
    }

    return newGradient;
};

/**
 * Applies a custom gradient to the selected path item.
 * @param {Object} gradientData - The gradient data.
 */
GRADIENT.applyCustomGradient = function (gradientData) {
    if (app.documents.length === 0) {
        return;
    }

    try {
        var gradient = GRADIENT._createGradient(gradientData);
        if (!gradient) {
            return;
        }
        var pathItem = app.activeDocument.selection.length > 0 ? app.activeDocument.selection[0] : null;
        if (!pathItem) {
            app.activeDocument.swatches.getByName(gradient.name) || app.activeDocument.swatches.add(gradient);
            return;
        }

        var gradientColor = new GradientColor();
        gradientColor.gradient = gradient;
        gradientColor.gradient.name = gradientData.name;
        gradientColor.hiliteLength = gradientData.hiliteLength || 0;
        gradientColor.hiliteAngle = gradientData.hiliteAngle || 0;
        gradientColor.angle = gradientData.angle || 0;

        var scaleX = (gradientData.scale || 1.0) * 100.0;
        var scaleY = scaleX * (gradientData.aspectRatio || 1.0);
        var matrix = app.getScaleMatrix(scaleX, scaleY);
        gradientColor.matrix = matrix;
        
        if (app.isFillActive()) {
            pathItem.fillColor = gradientColor;
            pathItem.filled = true;
            app.activeDocument.defaultFillColor = gradientColor;
        }

        if (app.isStrokeActive()) {
            pathItem.strokeColor = gradientColor;
            app.activeDocument.defaultStrokeColor = gradientColor;
        }

    } catch (ex) {
        alert('Failed to apply Gradient' + ex);
        $._ADBE_LIBS_CORE.writeToLog('ILST.jsx-applyCustomGradient()', ex);
    }
};

/**
 * Converts data representation to a gradient color
 * @param {Object} data - The gradient data.
 * @returns {Object} - The new Gradient Color object.
 */
GRADIENT.dataToGradientColor = function (data) {
    if (!data || !data.length) {
        return null;
    }

    var gradientData = data[0];
    // Create Gradient from data
    var gradient = GRADIENT._createGradient(gradientData);
    // Create a Gradient Color
    var gradientColor = new GradientColor();
    gradientColor.gradient = gradient;
    gradientColor.angle = gradientData.angle || 0;
    gradientColor.hiliteLength = gradientData.hiliteLength || 0;
    gradientColor.hiliteAngle = gradientData.hiliteAngle || 0;
    var scaleX = (gradientData.scale || 1.0) * 100.0;
    var scaleY = scaleX * (gradientData.aspectRatio || 1.0);
    var matrix = app.getScaleMatrix(scaleX, scaleY);
    gradientColor.matrix = matrix;
    return gradientColor;
};

GRADIENT.setGradientFillColor = function (color) {
    try {
        var newColor = GRADIENT.dataToGradientColor(color);
        app.activeDocument.defaultFillColor = newColor;
    } catch (ex) {
        $._ADBE_LIBS_CORE.writeToLog('ILST.jsx-setGradientFillColor()', ex);
    }
};

GRADIENT.setGradientStrokeColor = function (color) {
    try {
        var newColor = GRADIENT.dataToGradientColor(color);
        app.activeDocument.defaultStrokeColor = newColor;
    } catch (ex) {
        $._ADBE_LIBS_CORE.writeToLog('ILST.jsx-setGradientStrokeColor()', ex);
    }
};

GRADIENT.addGradientAsSwatch = function (color) {
    try {
        if (app.documents.length === 0) {
            return;
        }
        GRADIENT.dataToGradientColor(color);

    } catch (ex) {
        $._ADBE_LIBS_CORE.writeToLog('ILST.jsx-addGradientAsSwatch()', ex);
    }
};
