// $Id: profilechecker.cpp,v 1.48 2008/03/06 21:18:58 hvengel Exp $
//  Lttle cms Profiler
//  Copyright (C) 1998-2001 Marti Maria
// Copyright (C) 2005 Hal Engel
//
// THIS SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
// EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
// WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
//
// IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
// INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
// OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
// LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

//
// Version 1.11

#include <qstringlist.h>
#include <q3buttongroup.h>
#include <qcheckbox.h>
#include <qspinbox.h>
#include <qslider.h>
#include <q3filedialog.h>
#include <q3progressbar.h>
#include <qapplication.h>
#include <qvariant.h>
#include <qpushbutton.h>
#include <qlabel.h>
#include <qlineedit.h>
#include <qtoolbutton.h>
#include <qcombobox.h>
#include <qtabwidget.h>
#include <qwidget.h>
#include <q3groupbox.h>
#include <q3multilineedit.h>
#include <q3textview.h>
#include <q3table.h>
#include <q3buttongroup.h>
#include <qradiobutton.h>
#include <q3frame.h>
#include <qlayout.h>
#include <qtooltip.h>
#include <q3whatsthis.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qdir.h>
#include <qmessagebox.h>
//Added by qt3to4:
#include <QTranslator>
#include <QResizeEvent>

#include "profilechecker.h"
#include "lprofmain.h"

/* TRANSLATOR White point text for Profile Checker information screen */
QString WPnear = ProfileChecker::tr("White point near " ),
        WPunknown = ProfileChecker::tr("Unknown white point "),
        WPXYZ = ProfileChecker::tr("\nMedia white (XYZ):");

QString mess1 = ProfileChecker::tr("Display Profile Missing"),
        mess2 = ProfileChecker::tr("You do not have a display profile  "
                                   "specified.  Please go back to the  "
                                   "Preferences tab of the main LProf  "
                                   "dialog and select a display profile.");

typedef struct {
				const char *Label;
				QRgb rgb;

} LABELCOLOR,FAR* LPLABELCOLOR;

void ProfileChecker::slotHideTagetSelectorIfNeeded()
{
    char OutputProfileFile[1024];

    if (OutputFileEdit -> text().isEmpty () || !QFile::exists(OutputFileEdit -> text()))
    {
        QMessageBox mb( tr("Profile file name is not valid."),
                        tr("Please enter a valid profile file name."),
                        QMessageBox::Critical,
                        QMessageBox::Ok | QMessageBox::Default,
                        Qt::NoButton,  Qt::NoButton);

        mb.exec();
        return;
    }

    strcpy(OutputProfileFile,OutputFileEdit -> text().toLocal8Bit());
    cmsHPROFILE hProfile = cmsOpenProfileFromFile(OutputProfileFile, "r");
    if (cmsGetDeviceClass(hProfile) == icSigDisplayClass)
    {
       TargetsSelector->hide();
    }
    else
    {
        TargetsSelector->show();
    }
    cmsCloseProfile(hProfile);
}

ProfileChecker::ProfileChecker(QWidget *parent )
    : QDialog(parent, "", 0, Qt::WStyle_SysMenu | Qt::WStyle_MinMax | Qt::WStyle_Title),
    Checker(0)
{

   setupUi(this);
   QObject::connect(buttonOk, SIGNAL(clicked()), this, SLOT(close()));
   QObject::connect(buttonOk, SIGNAL(clicked()), this, SLOT(accept()));
   QObject::connect(TheGoButton, SIGNAL(clicked()), this, SLOT(slotGO()));
   QObject::connect(RadioPostA2B, SIGNAL(toggled(bool)), this, SLOT(slotChangeCurve()));
   QObject::connect(RadioPostB2A, SIGNAL(toggled(bool)), this, SLOT(slotChangeCurve()));
   QObject::connect(RadioPreA2B, SIGNAL(toggled(bool)), this, SLOT(slotChangeCurve()));
   QObject::connect(RadioPreB2A, SIGNAL(toggled(bool)), this, SLOT(slotChangeCurve()));
   QObject::connect(OutputFileSelBtn, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile()));
   QObject::connect(TabProfiler, SIGNAL(currentChanged(QWidget*)), this, SLOT(slotUpdateLabels()));
   QObject::connect(ComboBoxIntent, SIGNAL(activated(int)), this, SLOT(slotUpdateLabels()));
   QObject::connect(SelScanoutBtn, SIGNAL(clicked()), this, SLOT(slotSelectScanoutIT8()));
   QObject::connect(RadioTRC, SIGNAL(toggled(bool)), this, SLOT(slotChangeCurve()));
   QObject::connect(buttonHelp, SIGNAL(clicked()), this, SLOT(slotHelpButton()));
   QObject::connect(OutputFileEdit, SIGNAL(textChanged(QString)), this, SLOT(isAllReady()));
   QObject::connect(ComboBoxCorrection, SIGNAL(activated(int)), this, SLOT(slotChangeCorrection(int)));
   QObject::connect(OutputFileEdit, SIGNAL(selectionChanged()), this, SLOT(slotHideTagetSelectorIfNeeded()));
   Checker = new CheckProfile(ComboBoxCorrection);

   mainLabel -> setAutoFillBackground ( true ); 
   QPalette pal = mainLabel-> palette();
   pal.setColor(mainLabel ->  backgroundRole(), Qt::white);
   mainLabel -> setPalette(pal);
   
   checkerP chparms;
   QString per = ProfileChecker::tr("Perceptual"),
   relcolor = ProfileChecker::tr("Relative colorimetric"),
   sat = ProfileChecker::tr("Saturation"),
   Absolute = ProfileChecker::tr("Absolute");

   // ComboBoxIntent -> setEnabled(FALSE);

   ComboBoxIntent -> clear();
   ComboBoxIntent -> insertItem(QString::fromLocal8Bit("(*) ") + tr("Perceptual"));
   ComboBoxIntent -> insertItem(QString::fromLocal8Bit("(*) ") + tr("Relative colorimetric"));
   ComboBoxIntent -> insertItem(QString::fromLocal8Bit("(*) ") + tr("Saturation"));
   ComboBoxIntent -> insertItem(QString::fromLocal8Bit("(*) ") + tr("Absolute"));

   /* TRANSLATOR White point text for Profile Checker information screen */
   InfoView -> setText(QTranslator::tr("\n\nSelect the  profile to check. "
         "Optionally, you can select target reference and measurement for dE testing.\n\n"
         "Press 'Inspect Profile' when done."));

   ResetData(FALSE);
   chparms.get(chparms);
   OutputFileEdit->setText(chparms.items.profile);
   Scanout->setText(chparms.items.msheet);
   // TargetsSelector -> setDirCaption(QTranslator::tr(" Select target vendor && type "));
   TargetsSelector->Dir=chparms.items.ref_dir;
   TargetsSelector -> FillValues();
   // qDebug("cur_ref = %i", (int)chparms.items.cur_ref);
   TargetsSelector->setCurrItem((int)chparms.items.cur_ref);
   MonitorProfileSelector->Dir=chparms.items.mon_profile_dir;
   MonitorProfileSelector ->RestrictColorspace = icSigRgbData;
   MonitorProfileSelector ->RestrictClass = icSigDisplayClass;
   MonitorProfileSelector -> FillValues();
   MonitorProfileSelector->setFilename(chparms.items.mon_profile_file_name);

   // hide monitor profile page.  This value is passed from the main dialog
   TabProfiler->removePage(MonitorProfilePage);
   // CIETonge->setScaledContents(true);
   CurvePixLabel->setScaledContents(true);

   // Check for profile where a reference file should not be used
   // and hide TagetSelector if that is the case
   // slotHideTagetSelectorIfNeeded();
   slotGO();
   slotHideTagetSelectorIfNeeded();
}

static
void FreeGammaSet(LPGAMMATABLE Gamma[], int n, BOOL lFree)
{

	for (int i=0; i < n; i++) {
	    if (lFree)
                  {
                      if (Gamma[i] != NULL) cmsFreeGamma(Gamma[i]);
                  }
	   Gamma[i] = NULL;
	}
}

void ProfileChecker::isAllReady()
{
    QDir dir;

    if (OutputFileEdit -> text().isEmpty ())
    {
        TheGoButton -> setEnabled(false);
    }
    else
    {
        if (!dir.exists(OutputFileEdit -> text()))
            TheGoButton -> setEnabled(false);
        else
            TheGoButton -> setEnabled(true);
    }
}

void ProfileChecker::ResetMeasurement(BOOL lFree)
{
	if (lFree) {

	if (m.Patches)
		free(m.Patches);
	if (m.Allowed)
		free(m.Allowed);
	}

	ZeroMemory(&m, sizeof(MEASUREMENT));

}

// Trash data

void ProfileChecker::ResetData(BOOL lFree)
{

	FreeGammaSet(TRC, 3, lFree);
	for (int i=0; i < 3; i++) {

		FreeGammaSet(&A2B0Pre[i][0], MAXCHANNELS, lFree);
		FreeGammaSet(&A2B0Post[i][0], MAXCHANNELS, lFree);
		FreeGammaSet(&B2A0Pre[i][0], MAXCHANNELS, lFree);
		FreeGammaSet(&B2A0Post[i][0], MAXCHANNELS, lFree);
	}

	ResetMeasurement(lFree);
	ZeroMemory(&Primaries, sizeof(cmsCIExyYTRIPLE));
	ZeroMemory(&MediaWhite, sizeof(cmsCIEXYZ));

	TabProfiler -> setTabEnabled(ResultsTab, FALSE);
        TabProfiler -> setTabEnabled(CurvesTab, FALSE);
        TabProfiler -> setTabEnabled(DiagramTab, FALSE);

	RadioPreA2B  -> setEnabled(FALSE);
	RadioPostA2B -> setEnabled(FALSE);
	RadioPreB2A  -> setEnabled(FALSE);
	RadioPostB2A -> setEnabled(FALSE);
	RadioTRC -> setEnabled(FALSE);
        isAllReady();
}

ProfileChecker::~ProfileChecker()
{
    dialogSize ds;

    ds.put(profChecker, this -> height(), this -> width());
    ResetData();
    ReferenceSheet[0] = MeasurementSheet[0] = OutputProfileFile[0] = 0;

    delete Checker;
}

static
void GrabCurvesFromLUT(cmsHPROFILE hProfile, icTagSignature sig,
					  LPGAMMATABLE Pre[MAXCHANNELS], LPGAMMATABLE Post[MAXCHANNELS])

{
    LPLUT Lut = cmsReadICCLut(hProfile, sig);
    unsigned int i;

    for (i=0; i < Lut ->InputChan; i++) {

        Pre[i]  = cmsAllocGamma(Lut ->InputEntries);
        CopyMemory(Pre[i]->GammaTable, Lut ->L1[i], Lut ->InputEntries * sizeof(WORD));
        }

    for (i=0; i < Lut ->OutputChan; i++) {

        Post[i] = cmsAllocGamma(Lut->OutputEntries);
        CopyMemory(Post[i]->GammaTable, Lut ->L2[i], Lut ->OutputEntries * sizeof(WORD));
        }

    cmsFreeLUT(Lut);
}

static
const QString SupportedIntent(cmsHPROFILE hProfile, int nIntent)
{
    QString Buffer;
    int AsInput, AsOutput;

    const QString Intents[4] = {QString::fromLocal8Bit("Perceptual"), QString::fromLocal8Bit("Relative colorimetric"), QString::fromLocal8Bit("Saturation"), QString::fromLocal8Bit("Absolute")};
    // none, input only, output only, full
    const QString Mode[4]    = {QString::fromLocal8Bit("(*) "), QString::fromLocal8Bit("(i) "), QString::fromLocal8Bit("(o) "), QString::fromLocal8Bit("" )};

    AsInput  = cmsIsIntentSupported(hProfile, nIntent, LCMS_USED_AS_INPUT) ? 1 : 0;
    AsOutput = cmsIsIntentSupported(hProfile, nIntent, LCMS_USED_AS_OUTPUT) ? 2 : 0;

    Buffer = Mode[AsInput + AsOutput] + QTranslator::tr(Intents[nIntent].toLocal8Bit());

    return Buffer;
}

static
void ScaleToWhite(LPcmsCIEXYZ WtPt, LPcmsCIEXYZ Src)
{

    Src->X = (Src -> X * WtPt ->X ) / cmsD50_XYZ() -> X;
    Src->Y = (Src -> Y * WtPt ->Y ) / cmsD50_XYZ() -> Y;
    Src->Z = (Src -> Z * WtPt ->Z ) / cmsD50_XYZ() -> Z;

}

// Open profile and grab all needed information
// FIXME TODO this code really needs to be rewritten not to rely on C string formatting and static buffers

void ProfileChecker::InspectProfile()
{
    QString buffer;
    int i;
    char temp[40];
    char temp2[30];
    char Desc[1024];
    char Copyright[2048];
    char MonCal[1024];
    char WhiteStr[1024];
    cmsCIEXYZ WhitePt;

    if (MonitorProfileSelector ->getFilename().length() == 0 )
    {
        QMessageBox mb( mess1,
                        mess2,
                        QMessageBox::Critical,
                        QMessageBox::Ok | QMessageBox::Default,
                        Qt::NoButton,  Qt::NoButton);

        mb.exec();
        return;
    }

    ResetData();
    ReferenceSheet[0] = MeasurementSheet[0] = OutputProfileFile[0] = 0;

    // We need a profile at least
    if (OutputFileEdit -> text().isEmpty () || !QFile::exists(OutputFileEdit -> text()))
    {
        QMessageBox mb( tr("Profile file name is not valid."),
                        tr("Please enter a valid profile file name."),
                        QMessageBox::Critical,
                        QMessageBox::Ok | QMessageBox::Default,
                        Qt::NoButton,  Qt::NoButton);

        mb.exec();
        return;
    }
    strcpy(OutputProfileFile,OutputFileEdit -> text().toLocal8Bit());
    // Maybe some reference sheet
    QString cTarget = TargetsSelector -> getFilename();
    if (cTarget != QString::null)
        strcpy(ReferenceSheet, cTarget.toLocal8Bit());
    // And measurement sheet
    QString cScanout = Scanout -> text();
    if (cScanout != QString::null)
        strcpy(MeasurementSheet, cScanout.toLocal8Bit());
    if (!QFile::exists(QString::fromLocal8Bit(MeasurementSheet)))
    {
        QMessageBox mb( tr("Measurement sheet file name is not valid."),
                        tr("Please enter a valid Measurement sheet file name."),
                        QMessageBox::Critical,
                        QMessageBox::Ok | QMessageBox::Default,
                        Qt::NoButton,  Qt::NoButton);

        mb.exec();
        return;
    }
    // Go on.. open profile
    cmsHPROFILE hProfile = cmsOpenProfileFromFile(OutputProfileFile, "r");
    if (cmsGetDeviceClass(hProfile) == icSigDisplayClass)
    {
        strcpy(ReferenceSheet, "");
    }
    else if (!QFile::exists(QString::fromLocal8Bit(ReferenceSheet)))
    {
        QMessageBox mb( tr("Reference sheet file name is not valid."),
                        tr("Please enter a valid referance sheet file name."),
                        QMessageBox::Critical,
                        QMessageBox::Ok | QMessageBox::Default,
                        Qt::NoButton,  Qt::NoButton);

        mb.exec();
        return;
    }
    PCSColorSpace     = cmsGetPCS(hProfile);
    ProfileColorSpace = cmsGetColorSpace(hProfile);

    InfoView -> setText(QTranslator::tr("\nProfile: ") + QString::fromLocal8Bit(cmsTakeProductName(hProfile)));
    // InfoView -> append((QString) "\n" + cmsTakeProductInfo(hProfile));
    if (cmsIsTag(hProfile, icSigProfileDescriptionTag))
    {
        cmsReadICCText(hProfile, icSigProfileDescriptionTag, Desc);
        strcat(Desc, "\r\n\r\n");
        InfoView -> append(QString::fromLocal8Bit("\n") + QString::fromLocal8Bit(Desc));

    }
    if (cmsIsTag(hProfile, icSigCopyrightTag))
    {
        cmsReadICCText(hProfile, icSigCopyrightTag, Copyright);
        strcat(Copyright, "\r\n\r\n");
        InfoView -> append(QString::fromLocal8Bit(Copyright));
    }
    // KODAK private tag... But very useful

#define K007         (icTagSignature)0x4B303037

       // MonCal
    if (cmsIsTag(hProfile, K007))
    {
        cmsReadICCText(hProfile, K007, MonCal);
        strcat(MonCal, "\r\n\r\n");
        InfoView -> append(QString::fromLocal8Bit(MonCal));
    }
    else
    {
        cmsTakeMediaWhitePoint(&WhitePt, hProfile);
        _cmsIdentifyWhitePoint(WhiteStr, &WhitePt);

        if (strncmp(WhiteStr, "WhitePoint", 10) ==0)
        {
            strcpy(temp, "White point near");
            strcat(temp, " ");
            buffer = tr(temp);
            strcpy(temp2, strtok(WhiteStr, ":"));
            strcpy(temp2, strtok(NULL, "\0"));
            buffer = buffer + QString::fromLocal8Bit(temp2);

        }
        else
        {
            strcpy(temp, strtok(WhiteStr, " "));
            strcat(temp, " ");
            for (i=2; i<=3; i++)
            {
               strcat(temp, strtok(NULL, " "));
               strcat(temp, " ");
            }
            buffer = tr(temp);
            if (strncmp(WhiteStr, "White", 5)==0)
            {
                strcpy(temp2, strtok(NULL, "K"));
                strcat(temp2, "K");
            }
            else
            {
                strcpy(temp2, strtok(NULL, ")"));
                strcat(temp2, ")");
            }
            buffer = buffer + QString::fromLocal8Bit(temp2);
        }
        InfoView -> append(buffer);
    }


    // The white point is REQUIRED
    cmsTakeMediaWhitePoint(&MediaWhite, hProfile);

    cmsCIExyY White;
    cmsXYZ2xyY(&White, &MediaWhite);

    buffer = tr("\nMedia white (XYZ):") +
             buffer.sprintf(" %3.2f, %3.2f, %3.2f",
                MediaWhite.X*100., MediaWhite.Y*100., MediaWhite.Z*100.);
    InfoView -> append(buffer);

    // The colorant matrix is optional

    ZeroMemory(&Primaries, sizeof(cmsCIExyYTRIPLE));
    if (cmsIsTag(hProfile, icSigRedColorantTag) &&
        cmsIsTag(hProfile, icSigGreenColorantTag) &&
        cmsIsTag(hProfile, icSigBlueColorantTag)) {

        MAT3 Mat;

        if (cmsReadICCMatrixRGB2XYZ(&Mat, hProfile)) {
            // Undo chromatic adaptation
           if (cmsAdaptMatrixFromD50(&Mat, &White)) {
               cmsCIEXYZ tmp;
               tmp.X = Mat.v[0].n[0];
               tmp.Y = Mat.v[1].n[0];
               tmp.Z = Mat.v[2].n[0];
	// ScaleToWhite(&MediaWhite, &tmp);
              cmsXYZ2xyY(&Primaries.Red, &tmp);
              tmp.X = Mat.v[0].n[1];
              tmp.Y = Mat.v[1].n[1];
              tmp.Z = Mat.v[2].n[1];
             // ScaleToWhite(&MediaWhite, &tmp);
             cmsXYZ2xyY(&Primaries.Green, &tmp);
             tmp.X = Mat.v[0].n[2];
             tmp.Y = Mat.v[1].n[2];
             tmp.Z = Mat.v[2].n[2];
             // ScaleToWhite(&MediaWhite, &tmp);
            cmsXYZ2xyY(&Primaries.Blue, &tmp);
            buffer = tr("Primaries:") + buffer.sprintf(" R:%1.2g, %1.2g  G:%1.2g, %1.2g  B:%1.2g, %1.2g",
                        Primaries.Red.x, Primaries.Red.y,
                        Primaries.Green.x, Primaries.Green.y,
                        Primaries.Blue.x, Primaries.Blue.y);
           InfoView -> append(buffer);
           }
       }
    }


    // The TRC tables are optional
    if (cmsIsTag(hProfile, icSigRedTRCTag) &&
        cmsIsTag(hProfile, icSigGreenTRCTag) &&
        cmsIsTag(hProfile, icSigBlueTRCTag))
    {
        TRC[0] = cmsReadICCGamma(hProfile, icSigRedTRCTag);
        TRC[1] = cmsReadICCGamma(hProfile, icSigGreenTRCTag);
        TRC[2] = cmsReadICCGamma(hProfile, icSigBlueTRCTag);
        RadioTRC -> setEnabled(TRUE);
        double gr, gg, gb;
        gr = cmsEstimateGamma(TRC[0]);
        gg = cmsEstimateGamma(TRC[1]);
        gb = cmsEstimateGamma(TRC[2]);
        if (gr > 0 && gg > 0 && gb > 0)
        {
            buffer = tr("Estimated gamma:") + buffer.sprintf(" R:%1.3g, G:%1.3g  B:%1.3g", gr, gg, gb);
            InfoView -> append(buffer);
        }
    }

    // Now on LUT's (Also optional)

    // need to do this for shaper TRC to?

    if (cmsIsTag(hProfile, icSigAToB0Tag))
    {
        GrabCurvesFromLUT(hProfile, icSigAToB0Tag, A2B0Pre[0], A2B0Post[0]);
        RadioPreA2B  -> setEnabled(TRUE);
        RadioPostA2B -> setEnabled(TRUE);
    }

    if (cmsIsTag(hProfile, icSigAToB1Tag))
    {
        GrabCurvesFromLUT(hProfile, icSigAToB1Tag, A2B0Pre[1], A2B0Post[1]);
        RadioPreA2B  -> setEnabled(TRUE);
        RadioPostA2B -> setEnabled(TRUE);
    }

    if (cmsIsTag(hProfile, icSigAToB2Tag))
    {
        GrabCurvesFromLUT(hProfile, icSigAToB2Tag, A2B0Pre[2], A2B0Post[2]);
        RadioPreA2B  -> setEnabled(TRUE);
        RadioPostA2B -> setEnabled(TRUE);
    }

    if (cmsIsTag(hProfile, icSigBToA0Tag))
    {
        GrabCurvesFromLUT(hProfile, icSigBToA0Tag, B2A0Pre[0], B2A0Post[0]);
        RadioPreB2A  -> setEnabled(TRUE);
        RadioPostB2A -> setEnabled(TRUE);
    }

    if (cmsIsTag(hProfile, icSigBToA1Tag))
    {
        GrabCurvesFromLUT(hProfile, icSigBToA1Tag, B2A0Pre[1], B2A0Post[1]);
        RadioPreB2A  -> setEnabled(TRUE);
        RadioPostB2A -> setEnabled(TRUE);
    }

    if (cmsIsTag(hProfile, icSigBToA2Tag))
    {
        GrabCurvesFromLUT(hProfile, icSigBToA2Tag, B2A0Pre[2], B2A0Post[2]);
        RadioPreB2A  -> setEnabled(TRUE);
        RadioPostB2A -> setEnabled(TRUE);
    }

    // Try to get target data stored in profile

    if (cmsTakeCharTargetData(hProfile, &CharTarget, &CharTargetSize))
    {
        LCMSHANDLE hSheet = cmsxIT8LoadFromMem(CharTarget, CharTargetSize);
        if (hSheet != NULL)
        {
            cmsxPCollLoadFromSheet(&m,  hSheet);
            cmsxIT8Free(hSheet);
            cmsxPCollValidatePatches(&m, PATCH_HAS_XYZ|PATCH_HAS_RGB);
        }
    }

    // If there are measurements, load them also

    if (ReferenceSheet[0] || MeasurementSheet[0])
    {
        // If already filled, this takes precedence

        ResetMeasurement(TRUE);
        cmsxPCollBuildMeasurement(&m, ReferenceSheet, MeasurementSheet, 											  PATCH_HAS_XYZ|PATCH_HAS_RGB);
    }

    if (m.nPatches > 0)
    {
        // We need D50 Lab for checking results

        QString Results;
        Checker->Results(ResultsGrid, Results,
                        &m,
                        OutputProfileFile,
                        MonitorProfileSelector->getFilename().toLocal8Bit());
        ResultsResume -> setText(Results);
        TabProfiler -> setTabEnabled(ResultsTab, TRUE);
    }

    TabProfiler -> setTabEnabled(CurvesTab, TRUE);
    TabProfiler -> setTabEnabled(DiagramTab, TRUE);

    ComboBoxIntent -> clear();
    ComboBoxIntent -> insertItem(SupportedIntent(hProfile, INTENT_PERCEPTUAL));
    ComboBoxIntent -> insertItem(SupportedIntent(hProfile, INTENT_RELATIVE_COLORIMETRIC));
    ComboBoxIntent -> insertItem(SupportedIntent(hProfile, INTENT_SATURATION));
    cmsCloseProfile(hProfile);

}

// Returns a label list

static
LPLABELCOLOR GetLabelColorSet(icColorSpaceSignature ColorSpace)
{

static LABELCOLOR GraySet[] = {
    { "Gray", qRgb(255, 255, 255) }};

static LABELCOLOR RGBSet[] = {
	{ "Red", qRgb(255, 128, 128)},
	{ "Green", qRgb(128, 255, 128)},
	{ "Blue", qRgb(128, 128, 255)}};

	static LABELCOLOR CMYSet[] = {
	{ "Cyan",	 qRgb(128, 255, 255)},
	{ "Magenta", qRgb(255, 128, 255)},
	{ "Yellow",  qRgb(255, 255, 128)}};

    static LABELCOLOR CMYKSet[] = {
	{ "Cyan",	 qRgb(128, 255, 255)},
	{ "Magenta", qRgb(255, 128, 255)},
	{ "Yellow",  qRgb(255, 255, 128)},
	{ "Black",   qRgb(255, 255, 255)}};

	static LABELCOLOR YCbCrSet[] = {
	{ "Y",  qRgb(255, 255, 255)},
	{ "Cb",	 qRgb(128, 128, 255)},
	{ "Cr",  qRgb(255, 128, 128)}};

	static LABELCOLOR XYZSet[] = {
	{ "X", qRgb(255, 128, 128)},
	{ "Y", qRgb(255, 255, 255)},
	{ "Z", qRgb(128, 128, 255)}};

	static LABELCOLOR LabSet[] = {
	{ "L*",  qRgb(255, 255, 255)},
	{ "a*",	 qRgb(128, 255, 255)},
	{ "b*",  qRgb(255, 128, 255)}};


	static LABELCOLOR HexaSet[] = {
	{ "Cyan",	 qRgb(128, 255, 255)},
	{ "Magenta", qRgb(255, 128, 255)},
	{ "Yellow",  qRgb(255, 255, 128)},
	{ "Black",   qRgb(255, 255, 255)},
	{ "Orange",  qRgb(255, 128, 0) },
	{ "Green",   qRgb(128, 255, 128)}};

	static LABELCOLOR DefaultSet[] = {
	{ "CH1",  qRgb(255, 255, 255)},
	{ "CH2",  qRgb(255, 255, 255)},
	{ "CH3",  qRgb(255, 255, 255)},
	{ "CH4",  qRgb(255, 255, 255)},
	{ "CH5",  qRgb(255, 255, 255)},
	{ "CH6",  qRgb(255, 255, 255)},
	{ "CH7",  qRgb(255, 255, 255)},
	{ "CH8",  qRgb(255, 255, 255)},
	{ "CH9",  qRgb(255, 255, 255)},
	{ "CH10",  qRgb(255, 255, 255)},
	{ "CH11",  qRgb(255, 255, 255)},
	{ "CH12",  qRgb(255, 255, 255)},
	{ "CH13",  qRgb(255, 255, 255)},
	{ "CH14",  qRgb(255, 255, 255)},
	{ "CH15",  qRgb(255, 255, 255)},
	{ "CH16",  qRgb(255, 255, 255)}};


	switch (ColorSpace) {

	case icSigGrayData: return GraySet;
	case icSigRgbData: return RGBSet;
	case icSigCmyData: return CMYSet;
	case icSigCmykData: return CMYKSet;
	case icSigYCbCrData: return YCbCrSet;
	case icSigHexachromeData: return HexaSet;
	case icSigXYZData: return XYZSet;
	case icSigLabData: return LabSet;
	default: return DefaultSet;

	}
}


// Draw one set of curves

static
void DrawOneSet(cmsxDrawCurve* Curve, LPGAMMATABLE Tab[], icColorSpaceSignature ColorSpace)
{
    LPLABELCOLOR Labels;
    int nCurves = _cmsChannelsOf(ColorSpace);

    Labels = GetLabelColorSet(ColorSpace);
    for (int i=0; i < nCurves; i++)
    {
        if (Tab[i]) Curve->DrawGammaCurve(Tab[i], Labels[i].Label, Labels[i].rgb, i);
    }
}

int  ProfileChecker::GetIntent(void)
{
    return ComboBoxIntent -> currentItem();
}

void ProfileChecker::RedrawCurve()
{
   // char buff[128];
  // qDebug("RedrawCurve");

    if (TabProfiler -> currentPage() != CurvesTab) return;

    int w = CurvePixLabel-> width() - 2;
    int h = CurvePixLabel-> height() - 2;
    // sprintf(buff,"w = %i", w);
    // qDebug(buff);
    // sprintf(buff, "h = %i", h);
    // qDebug(buff);
    int intent = GetIntent();

    QPixmap* Pix = new QPixmap(w, h);

    cmsxDrawCurve Curve(*Pix);

    if (RadioTRC -> isChecked())
    {
        DrawOneSet(&Curve, TRC, icSigRgbData);
    }
    else
        if (RadioPreA2B -> isChecked())
        {
            DrawOneSet(&Curve, A2B0Pre[intent], ProfileColorSpace);
        }
    else
        if (RadioPostA2B -> isChecked())
        {
            DrawOneSet(&Curve, A2B0Post[intent], PCSColorSpace);
        }
    else
        if (RadioPreB2A -> isChecked())
        {
            DrawOneSet(&Curve, B2A0Pre[intent], PCSColorSpace);
        }
    else
        if (RadioPostB2A -> isChecked())
        {
            DrawOneSet(&Curve, B2A0Post[intent], ProfileColorSpace);
        }
    CurvePixLabel  ->setPixmap(*Pix);
    delete Pix;
}


void ProfileChecker::RedrawTonge()
{
    // char buff[128];
    // qDebug("RedrawTonge");
    if (TabProfiler -> currentPage() != DiagramTab) return;
    return;
}

void ProfileChecker::resizeEvent(QResizeEvent*)
{
    // qDebug("resize event")
    slotUpdateLabels();
}

void ProfileChecker::slotUpdateLabels()
{
    if (TabProfiler -> currentPage() == CurvesTab) ComboBoxIntent -> show();
    else ComboBoxIntent -> hide();
    if (TabProfiler -> currentPage() == ResultsTab) ComboBoxCorrection -> show();
    else ComboBoxCorrection -> hide();

    RedrawTonge();
    RedrawCurve();
}

void ProfileChecker::slotSelectOutputFile()
{

    QString fn = Q3FileDialog::getOpenFileName( QString::null,
                                               QTranslator::tr("icc profiles (*.icc *.icm)\nAll files (*.*)"),
                                                this,
                                                "",
                                                QTranslator::tr("Select profile filename"));

    if (fn != QString::null)
            SetInputProfile(fn);


}

void ProfileChecker::SetScanoutFile(const QString ScanoutFile)
{
    Scanout -> setText(ScanoutFile);
}

void ProfileChecker::SetInputProfile(const QString OutputFile)
{
    OutputFileEdit -> setText(OutputFile);
}


void ProfileChecker::slotSelectScanoutIT8()
{

    QString fn = Q3FileDialog::getOpenFileName( QString::fromLocal8Bit(""),
                                               QTranslator::tr("IT8/CGATS.5 Files (*.it? *.cgt)\nAll files (*.*)"),
                                                this,
                                                "",
                                                QTranslator::tr("Select measurement filename"));

    if (fn != QString::null)
            SetScanoutFile(fn);

}

void ProfileChecker::slotGO()
{
    QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) );
    InspectProfile();
    slotUpdateLabels();
    CIETonge -> DrawTonge(&Primaries, &MediaWhite, &m);
    QApplication::restoreOverrideCursor();
    dialogSize ds;

    ds.put(profChecker, this -> height(), this -> width());
}

void ProfileChecker::slotChangeCorrection(int newItem)
{
    // if (TabProfiler->isTabEnabled(ResultsTab))
    int i = TabProfiler->currentPageIndex();
    slotGO();
    TabProfiler->setTabEnabled(ResultsTab, TRUE);
    TabProfiler->setCurrentPage(i);
}

void ProfileChecker::slotChangeCurve()
{
    RedrawCurve();
}

void ProfileChecker::slotHelpButton()
{
     QString path = get_global_help_path() + QString::fromLocal8Bit("/checker.html");
     qDebug(path.toLocal8Bit());
     getHelp()->openAssistant ();
     getHelp()->showPage(path);
}



