/*
 *  SPDX-FileCopyrightText: 2005 Adrian Page <adrian@pagenet.plus.com>
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include "KoCompositeOpRegistry.h"

#include <QGlobalStatic>
#include <QList>

#include <KLocalizedString>

#include "KoColorSpace.h"
#include "KoCompositeOp.h"
#include <KoID.h>

#include <algorithm>

Q_GLOBAL_STATIC(KoCompositeOpRegistry, registry)

KoCompositeOpRegistry::KoCompositeOpRegistry()
{
    m_categories << KoID("arithmetic", i18n("Arithmetic")) << KoID("dark", i18n("Darken")) << KoID("light", i18n("Lighten"))
                 << KoID("negative", i18n("Negative")) << KoID("mix", i18n("Mix")) << KoID("misc", i18n("Misc")) << KoID("hsy", i18n("HSY"))
                 << KoID("hsi", i18n("HSI")) << KoID("hsl", i18n("HSL")) << KoID("hsv", i18n("HSV"));

    m_map.insert(m_categories[0], KoID(COMPOSITE_ADD, i18n("Addition")));
    m_map.insert(m_categories[0], KoID(COMPOSITE_SUBTRACT, i18n("Subtract")));
    m_map.insert(m_categories[0], KoID(COMPOSITE_MULT, i18n("Multiply")));
    m_map.insert(m_categories[0], KoID(COMPOSITE_DIVIDE, i18n("Divide")));
    m_map.insert(m_categories[0], KoID(COMPOSITE_INVERSE_SUBTRACT, i18n("Inverse Subtract")));

    m_map.insert(m_categories[1], KoID(COMPOSITE_BURN, i18n("Burn")));
    m_map.insert(m_categories[1], KoID(COMPOSITE_LINEAR_BURN, i18n("Linear Burn")));
    m_map.insert(m_categories[1], KoID(COMPOSITE_DARKEN, i18n("Darken")));
    m_map.insert(m_categories[1], KoID(COMPOSITE_GAMMA_DARK, i18n("Gamma Dark")));
    m_map.insert(m_categories[1], KoID(COMPOSITE_DARKER_COLOR, i18n("Darker Color")));

    m_map.insert(m_categories[2], KoID(COMPOSITE_DODGE, i18n("Color Dodge")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_DODGE, i18n("Linear Dodge")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_LIGHTEN, i18n("Lighten")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_LINEAR_LIGHT, i18n("Linear Light")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_SCREEN, i18n("Screen")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_PIN_LIGHT, i18n("Pin Light")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_VIVID_LIGHT, i18n("Vivid Light")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_HARD_LIGHT, i18n("Hard Light")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_SOFT_LIGHT_PHOTOSHOP, i18n("Soft Light (Photoshop)")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_SOFT_LIGHT_SVG, i18n("Soft Light (SVG)")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_GAMMA_LIGHT, i18n("Gamma Light")));
    m_map.insert(m_categories[2], KoID(COMPOSITE_LIGHTER_COLOR, i18n("Lighter Color")));

    m_map.insert(m_categories[3], KoID(COMPOSITE_DIFF, i18n("Difference")));
    m_map.insert(m_categories[3], KoID(COMPOSITE_EQUIVALENCE, i18n("Equivalence")));
    m_map.insert(m_categories[3], KoID(COMPOSITE_ADDITIVE_SUBTRACTIVE, i18n("Additive Subtractive")));
    m_map.insert(m_categories[3], KoID(COMPOSITE_EXCLUSION, i18n("Exclusion")));
    m_map.insert(m_categories[3], KoID(COMPOSITE_ARC_TANGENT, i18n("Arcus Tangent")));

    m_map.insert(m_categories[4], KoID(COMPOSITE_OVER, i18n("Normal")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_BEHIND, i18n("Behind")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_GREATER, i18n("Greater")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_OVERLAY, i18n("Overlay")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_ERASE, i18n("Erase")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_ALPHA_DARKEN, i18n("Alpha Darken")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_MIX, i18n("Hard Mix")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_MERGE, i18n("Grain Merge")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_EXTRACT, i18n("Grain Extract")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_PARALLEL, i18n("Parallel")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_ALLANON, i18n("Allanon")));
    m_map.insert(m_categories[4], KoID(COMPOSITE_GEOMETRIC_MEAN, i18n("Geometric Mean")));

    m_map.insert(m_categories[5], KoID(COMPOSITE_BUMPMAP, i18n("Bumpmap")));
    m_map.insert(m_categories[5], KoID(COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Map")));
    m_map.insert(m_categories[5], KoID(COMPOSITE_DISSOLVE, i18n("Dissolve")));
    m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_RED, i18n("Copy Red")));
    m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_GREEN, i18n("Copy Green")));
    m_map.insert(m_categories[5], KoID(COMPOSITE_COPY_BLUE, i18n("Copy Blue")));
    m_map.insert(m_categories[5], KoID(COMPOSITE_COPY, i18n("Copy")));
    m_map.insert(m_categories[5], KoID(COMPOSITE_TANGENT_NORMALMAP, i18n("Tangent Normalmap")));

    m_map.insert(m_categories[6], KoID(COMPOSITE_COLOR, i18n("Color")));
    m_map.insert(m_categories[6], KoID(COMPOSITE_HUE, i18n("Hue")));
    m_map.insert(m_categories[6], KoID(COMPOSITE_SATURATION, i18n("Saturation")));
    m_map.insert(m_categories[6], KoID(COMPOSITE_LUMINIZE, i18n("Luminosity")));
    m_map.insert(m_categories[6], KoID(COMPOSITE_DEC_SATURATION, i18n("Decrease Saturation")));
    m_map.insert(m_categories[6], KoID(COMPOSITE_INC_SATURATION, i18n("Increase Saturation")));
    m_map.insert(m_categories[6], KoID(COMPOSITE_DEC_LUMINOSITY, i18n("Decrease Luminosity")));
    m_map.insert(m_categories[6], KoID(COMPOSITE_INC_LUMINOSITY, i18n("Increase Luminosity")));

    m_map.insert(m_categories[7], KoID(COMPOSITE_COLOR_HSI, i18n("Color HSI")));
    m_map.insert(m_categories[7], KoID(COMPOSITE_HUE_HSI, i18n("Hue HSI")));
    m_map.insert(m_categories[7], KoID(COMPOSITE_SATURATION_HSI, i18n("Saturation HSI")));
    m_map.insert(m_categories[7], KoID(COMPOSITE_INTENSITY, i18n("Intensity")));
    m_map.insert(m_categories[7], KoID(COMPOSITE_DEC_SATURATION_HSI, i18n("Decrease Saturation HSI")));
    m_map.insert(m_categories[7], KoID(COMPOSITE_INC_SATURATION_HSI, i18n("Increase Saturation HSI")));
    m_map.insert(m_categories[7], KoID(COMPOSITE_DEC_INTENSITY, i18n("Decrease Intensity")));
    m_map.insert(m_categories[7], KoID(COMPOSITE_INC_INTENSITY, i18n("Increase Intensity")));

    m_map.insert(m_categories[8], KoID(COMPOSITE_COLOR_HSL, i18n("Color HSL")));
    m_map.insert(m_categories[8], KoID(COMPOSITE_HUE_HSL, i18n("Hue HSL")));
    m_map.insert(m_categories[8], KoID(COMPOSITE_SATURATION_HSL, i18n("Saturation HSL")));
    m_map.insert(m_categories[8], KoID(COMPOSITE_LIGHTNESS, i18n("Lightness")));
    m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_SATURATION_HSL, i18n("Decrease Saturation HSL")));
    m_map.insert(m_categories[8], KoID(COMPOSITE_INC_SATURATION_HSL, i18n("Increase Saturation HSL")));
    m_map.insert(m_categories[8], KoID(COMPOSITE_DEC_LIGHTNESS, i18n("Decrease Lightness")));
    m_map.insert(m_categories[8], KoID(COMPOSITE_INC_LIGHTNESS, i18n("Increase Lightness")));

    m_map.insert(m_categories[9], KoID(COMPOSITE_COLOR_HSV, i18n("Color HSV")));
    m_map.insert(m_categories[9], KoID(COMPOSITE_HUE_HSV, i18n("Hue HSV")));
    m_map.insert(m_categories[9], KoID(COMPOSITE_SATURATION_HSV, i18n("Saturation HSV")));
    m_map.insert(m_categories[9], KoID(COMPOSITE_VALUE, i18n("Value")));
    m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_SATURATION_HSV, i18n("Decrease Saturation HSV")));
    m_map.insert(m_categories[9], KoID(COMPOSITE_INC_SATURATION_HSV, i18n("Increase Saturation HSV")));
    m_map.insert(m_categories[9], KoID(COMPOSITE_DEC_VALUE, i18n("Decrease Value")));
    m_map.insert(m_categories[9], KoID(COMPOSITE_INC_VALUE, i18n("Increase Value")));
}

const KoCompositeOpRegistry &KoCompositeOpRegistry::instance()
{
    return *registry;
}

KoID KoCompositeOpRegistry::getDefaultCompositeOp() const
{
    return KoID(COMPOSITE_OVER, i18n("Normal"));
}

KoID KoCompositeOpRegistry::getKoID(const QString &compositeOpID) const
{
    KoIDMap::const_iterator itr = std::find(m_map.begin(), m_map.end(), KoID(compositeOpID));
    return (itr != m_map.end()) ? *itr : KoID();
}

KoCompositeOpRegistry::KoIDMap KoCompositeOpRegistry::getCompositeOps() const
{
    return m_map;
}

KoCompositeOpRegistry::KoIDList KoCompositeOpRegistry::getCategories() const
{
    return m_categories;
}

KoCompositeOpRegistry::KoIDList KoCompositeOpRegistry::getCompositeOps(const KoID &category, const KoColorSpace *colorSpace) const
{
    qint32 num = m_map.count(category);
    KoIDMap::const_iterator beg = m_map.find(category);
    KoIDMap::const_iterator end = beg + num;

    KoIDList list;
    list.reserve(num);

    if (colorSpace) {
        for (; beg != end; ++beg) {
            if (colorSpace->hasCompositeOp(beg->id()))
                list.push_back(*beg);
        }
    } else {
        for (; beg != end; ++beg)
            list.push_back(*beg);
    }

    return list;
}

KoCompositeOpRegistry::KoIDList KoCompositeOpRegistry::getCompositeOps(const KoColorSpace *colorSpace) const
{
    KoIDMap::const_iterator beg = m_map.begin();
    KoIDMap::const_iterator end = m_map.end();

    KoIDList list;
    list.reserve(m_map.size());

    if (colorSpace) {
        for (; beg != end; ++beg) {
            if (colorSpace->hasCompositeOp(beg->id()))
                list.push_back(*beg);
        }
    } else {
        for (; beg != end; ++beg)
            list.push_back(*beg);
    }

    return list;
}

bool KoCompositeOpRegistry::colorSpaceHasCompositeOp(const KoColorSpace *colorSpace, const KoID &compositeOp) const
{
    return colorSpace ? colorSpace->hasCompositeOp(compositeOp.id()) : false;
}
