#include "dialogs.h"
#include "menuid.h"
#include "ifapp.h"
#include "catagorymgr.h"
#include "imageutils.h"
#include <qlistbox.h>
#include <qlistview.h>
#include <qpushbutton.h>
#include <qbuttongroup.h>
#include <qgroupbox.h>
#include <qvgroupbox.h>
#include <qinputdialog.h>
#include <qcombobox.h>
#include <qprinter.h>
#include <qpaintdevicemetrics.h>
#include <qlabel.h>
#include <qmessagebox.h>
#include <qvalidator.h>
#include <qlineedit.h>
#include <qlayout.h>
#include <kseparator.h>
#include <kmessagebox.h>
#include <kbuttonbox.h>
#include <klocale.h>
#include <kconfig.h>
#include <kglobal.h>
#include <math.h>

// conversions from koGlobal.h
#ifndef CONVERT_FUNCS_DEFINED
#define CONVERT_FUNCS_DEFINED
inline double convertMMToInch(double mm){return(mm*0.039370147);}
inline double convertInchToMM(double inch){return(inch*25.399956);}
#endif
inline double convertMMToInch(const QString& mm){return(mm.toDouble()*0.039370147);}
inline double convertInchToMM(const QString& inch){return(inch.toDouble()*25.399956);}


#define US_MEASURE 0
#define METRIC_MEASURE 1


KIFSizeDialog::KIFSizeDialog(int w, int h, QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    QVBoxLayout *layout = new QVBoxLayout(this, 4);
    wEdit = new KIntNumInput(w, this);
    wEdit->setLabel(i18n("Width"));
    wEdit->setRange(2, 6000);
    connect(wEdit, SIGNAL(valueChanged(int)), this,
            SLOT(slotWidthChanged(int)));
    layout->addWidget(wEdit);
    hEdit = new KIntNumInput(wEdit, h, this);
    hEdit->setLabel(i18n("Height"));
    hEdit->setRange(2, 6000);
    connect(hEdit, SIGNAL(valueChanged(int)), this,
            SLOT(slotHeightChanged(int)));
    layout->addWidget(hEdit);

    aspectCB = new QCheckBox(i18n("Maintain aspect ratio."), this);
    aspectCB->setChecked(true);
    layout->addWidget(aspectCB);
    layout->addStretch(1);

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    layout->addWidget(bbox);
    setCaption(i18n("Image Size"));
    origW = w;
    origH = h;
    ignoreSignals = false;
}

void KIFSizeDialog::slotWidthChanged(int newW)
{
    if(aspectCB->isChecked() && !ignoreSignals && newW != origW){
        ignoreSignals = true;
        float percent = ((float)newW)/((float)origW);
        qWarning("Width change of: %d to %d, percent: %f", origW, newW, percent);
        hEdit->setValue((int)(rint(origH*percent)));

        origH = hEdit->value();
        origW = wEdit->value();

        ignoreSignals = false;
    }

}

void KIFSizeDialog::slotHeightChanged(int newH)
{
    if(aspectCB->isChecked() && !ignoreSignals && newH != origH){
        ignoreSignals = true;
        float percent = ((float)newH)/((float)origH);
        qWarning("Height change of: %d to %d, percent: %f", origH, newH, percent);
        wEdit->setValue((int)(rint(origW*percent)));

        origH = hEdit->value();
        origW = wEdit->value();

        ignoreSignals = false;
    }

}

KIFSlideDialog::KIFSlideDialog(QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    KConfig *config = KGlobal::config();
    config->setGroup("SlideShow");
    setCaption(i18n("SlideShow"));
    QVBoxLayout *layout = new QVBoxLayout(this, 4);

    btnGrp = new QButtonGroup(i18n("Slideshow source"), this);
    QVBoxLayout *btnLayout = new QVBoxLayout(btnGrp, 5, 5);
    btnLayout->addSpacing(12);
    dirListBtn = new QRadioButton(i18n("Use images in current browser folder\n(or the current selection)"),
                                  btnGrp);
    btnLayout->addWidget(dirListBtn);
    fileListBtn = new QRadioButton(i18n("Use images in filelist"), btnGrp);
    btnLayout->addWidget(fileListBtn);
    layout->addWidget(btnGrp);

    btnGrp->setButton(config->readNumEntry("Source", 0));

    QVGroupBox *paramBox = new QVGroupBox(i18n("Slideshow options"), this);
    delayEdit = new KIntNumInput(config->readNumEntry("Delay", 5), paramBox);
    delayEdit->setLabel(i18n("Delay in seconds"), AlignVCenter);
    maxCB = new QCheckBox(i18n("Scale to screen size (maxpect)"), paramBox);
    maxCB->setChecked(config->readBoolEntry("Maxpect", false));
    loopCB = new QCheckBox(i18n("Loop"), paramBox);
    loopCB->setChecked(config->readBoolEntry("Loop", false));
    layout->addWidget(paramBox);

    QVGroupBox *effectGrpBox = new QVGroupBox(i18n("Effects"), this);
    effectBox = new QComboBox(effectGrpBox);
    effectBox->insertItem(i18n("None"), NoSlideEffectID);
    effectBox->insertItem(i18n("Blend"), BlendSlideEffectID);
    effectBox->insertItem(i18n("Fade"), FadeSlideEffectID);
    effectBox->setCurrentItem(config->readNumEntry("Effect",
                                                   NoSlideEffectID));
    aniDelayEdit = new KIntNumInput(config->readNumEntry("AniFrameDelay", 150),
                                    effectGrpBox);
    aniDelayEdit->setLabel(i18n("Delay between frames(ms)"), AlignVCenter);
    layout->addWidget(effectGrpBox);

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
   
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(slotAccepted()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addWidget(bbox);         
}

void KIFSlideDialog::slotAccepted()
{
    KConfig *config = KGlobal::config();
    config->setGroup("SlideShow");
    config->writeEntry("Source", btnGrp->id(btnGrp->selected()));
    config->writeEntry("Delay", delayEdit->value());
    config->writeEntry("Maxpect", maxCB->isChecked());
    config->writeEntry("Loop", loopCB->isChecked());
    config->writeEntry("Effect", effectBox->currentItem());
    config->writeEntry("AniFrameDelay", aniDelayEdit->value());
    config->setGroup("UIManager"); // just to make sure I don't screw up
    config->sync();
    accept();
}

int KIFSlideDialog::effect()
{
    return(effectBox->currentItem());
}

CatagoryDialog::CatagoryDialog(QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    QGridLayout *layout = new QGridLayout(this, 1, 1, 5);
    listBox = new QListBox(this);
    listBox->setSelectionMode(QListBox::Extended);
    listBox->setMinimumSize(300, 100);
    connect(listBox, SIGNAL(selectionChanged()), this,
            SLOT(slotSelectionChanged()));
    layout->addMultiCellWidget(listBox, 1, 3, 0, 0);
    QPushButton *newBtn = new QPushButton(i18n("New..."), this);
    connect(newBtn, SIGNAL(clicked()), this, SLOT(slotAdd()));
    layout->addWidget(newBtn, 1, 1);
    removeBtn = new QPushButton(i18n("Remove"), this);
    removeBtn->setEnabled(false);
    connect(removeBtn, SIGNAL(clicked()), this, SLOT(slotRemove()));
    layout->addWidget(removeBtn, 2, 1);
    KSeparator *sep = new KSeparator(Qt::Horizontal, this);
    layout->addMultiCellWidget(sep, 4, 4, 0, 1);

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addMultiCellWidget(bbox, 5, 5, 0, 1);

    layout->setRowStretch(3, 1);
    layout->setColStretch(0, 1);

    modified = false;
    // load initial list
    QString **array = kifapp()->catagoryManager()->array();
    QStringList strList;
    int i;
    for(i=1; i < 256; ++i){
        if(array[i] != NULL)
            strList.append(*array[i]);
    }
    if(!strList.isEmpty()){
        strList.sort();
        listBox->insertStringList(strList);
    }

    setCaption("Pixie File Catagories");
}

void CatagoryDialog::slotAdd()
{
    bool ok;
    QString str = QInputDialog::getText(i18n("New Catagory"),
                                        i18n("Please enter a name for the new catagory:"),
                                        QLineEdit::Normal,
                                        QString::null, &ok, this);
    if(ok){
        if(listBox->findItem(str, Qt::CaseSensitive | Qt::BeginsWith) != 0){
            KMessageBox::sorry(this, i18n("Category already exists."));
            return;
        }
        else{
            listBox->insertItem(str);
            listBox->sort();
            int id = listBox->index(listBox->findItem(str, Qt::CaseSensitive |
                                                      Qt::BeginsWith));
            if(!listBox->itemVisible(id))
                listBox->setTopItem(id);
            modified = true;
        }
    }
}

void CatagoryDialog::slotRemove()
{
    // we need this funky stringlist because you can't just loop and remove
    // multiselected items, since removing items changes the selection
    QStringList strList;
    unsigned int i;
    for(i=0; i < listBox->count(); ++i){
        if(!listBox->item(i)->isSelected())
            strList.append(listBox->text(i));
    }
    listBox->clear();
    listBox->insertStringList(strList);
    modified = true;
}

void CatagoryDialog::slotSelectionChanged()
{
    unsigned int i;
    for(i=0; i < listBox->count(); ++i){
        if(listBox->item(i)->isSelected()){
            removeBtn->setEnabled(true);
            return;
        }
    }
    removeBtn->setEnabled(false);
}

void CatagoryDialog::sync()
{
    if(!modified)
        return;
    QStringList strList;
    unsigned int i;
    for(i=0; i < listBox->count(); ++i){
        strList.append(listBox->text(i));
    }
    kifapp()->catagoryManager()->insertStringList(strList);
    kifapp()->catagoryManager()->sync();
}

KIFPrintDialog::KIFPrintDialog(KPrinter &p, QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    doSave = false;
    p.setFullPage(true);
    QPaintDeviceMetrics metrics(&p);
    KConfig *config = KGlobal::config();
    config->setGroup("Print");

    setCaption(i18n("Page Layout"));
    QVBoxLayout *layout = new QVBoxLayout(this, 4);
    QGroupBox *mBox = new QGroupBox(i18n("Margins"), this);
    QGridLayout *mLayout = new QGridLayout(mBox, 1, 1, 4);
    mLayout->addRowSpacing(0, 15);
    metricBox = new QComboBox(mBox);
    metricBox->insertItem(i18n("Inches"), US_MEASURE);
    metricBox->insertItem(i18n("Millimeters"), METRIC_MEASURE);
    metricBox->setCurrentItem(config->readNumEntry("MetricType", US_MEASURE));
    connect(metricBox, SIGNAL(activated(int)), this,
            SLOT(slotMetricsClicked(int)));
    mLayout->addMultiCellWidget(metricBox, 1, 1, 0, 2);

    double defHMargin, defVMargin;
    QSize margin = p.margins();
    defHMargin = ((double)margin.width())/metrics.logicalDpiX();
    defVMargin = ((double)margin.height())/metrics.logicalDpiY();
    if(metricBox->currentItem() == METRIC_MEASURE){
        defHMargin = convertInchToMM(defHMargin);
        defVMargin = convertInchToMM(defVMargin);
    }

    validator = new QDoubleValidator(this);
    validator->setDecimals(2);
    QLabel *lbl = new QLabel(i18n("Left:"), mBox);
    mLayout->addWidget(lbl, 2, 0);
    lEdit = new
        QLineEdit(QString::number(config->readDoubleNumEntry("LMargin", defHMargin)),
                  mBox);
    lEdit->setValidator(validator);
    mLayout->addWidget(lEdit, 2, 1);
    lbl = new QLabel(i18n("Right:"), mBox);
    mLayout->addWidget(lbl, 2, 3);
    rEdit = new
        QLineEdit(QString::number(config->readDoubleNumEntry("RMargin", defHMargin)),
                  mBox);
    rEdit->setValidator(validator);
    mLayout->addWidget(rEdit, 2, 4);

    lbl = new QLabel(i18n("Top:"), mBox);
    mLayout->addWidget(lbl, 3, 0);
    tEdit = new
        QLineEdit(QString::number(config->readDoubleNumEntry("TMargin", defVMargin)),
                  mBox);
    tEdit->setValidator(validator);
    mLayout->addWidget(tEdit, 3, 1);
    lbl = new QLabel(i18n("Bottom:"), mBox);
    mLayout->addWidget(lbl, 3, 3);
    bEdit = new
        QLineEdit(QString::number(config->readDoubleNumEntry("BMargin", defVMargin)),
                  mBox);
    bEdit->setValidator(validator);
    mLayout->addWidget(bEdit, 3, 4);

    mLayout->addColSpacing(2, 15);
    mLayout->setColStretch(5, 100);
    qWarning("HMargin: %f, VMargin: %f", defHMargin, defVMargin);
    layout->addWidget(mBox);

    scaleLarge = new QCheckBox(i18n("Scale large images to page size."), this);
    scaleLarge->setChecked(config->readBoolEntry("Scale", true));
    connect(scaleLarge, SIGNAL(clicked()), this, SLOT(slotOptionClicked()));
    layout->addWidget(scaleLarge);
    zoomSmall = new QCheckBox(i18n("Zoom small images to page size."), this);
    zoomSmall->setChecked(config->readBoolEntry("Zoom", false));
    connect(scaleLarge, SIGNAL(clicked()), this, SLOT(slotOptionClicked()));
    layout->addWidget(zoomSmall);
    manualDither = new QCheckBox(i18n("Manually dither highcolor pictures."),
                                 this);
    manualDither->setChecked(config->readBoolEntry("Dither", false));
    connect(scaleLarge, SIGNAL(clicked()), this, SLOT(slotOptionClicked()));
    layout->addWidget(manualDither);


    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
   
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addWidget(bbox);         
}

void KIFPrintDialog::slotOptionClicked()
{
    doSave = true;
    /*
    KConfig *config = KGlobal::config();
    config->setGroup("Print");
    config->writeEntry("Scale", scaleLarge->isChecked());
    config->writeEntry("Zoom", zoomSmall->isChecked());
    config->writeEntry("Dither", manualDither->isChecked());
    config->sync();*/
}

void KIFPrintDialog::slotMetricsClicked(int id)
{
    /*
    KConfig *config = KGlobal::config();
    config->setGroup("Print");
    config->writeEntry("MetricType", id);
    config->sync();
    */
    doSave = true;
    if(id == METRIC_MEASURE){
        lEdit->setText(QString::number(convertInchToMM(lEdit->text())));
        rEdit->setText(QString::number(convertInchToMM(rEdit->text())));
        tEdit->setText(QString::number(convertInchToMM(tEdit->text())));
        bEdit->setText(QString::number(convertInchToMM(bEdit->text())));

    }
    else{
        lEdit->setText(QString::number(convertMMToInch(lEdit->text())));
        rEdit->setText(QString::number(convertMMToInch(rEdit->text())));
        tEdit->setText(QString::number(convertMMToInch(tEdit->text())));
        bEdit->setText(QString::number(convertMMToInch(bEdit->text())));
    }

}

void KIFPrintDialog::accept()
{
    qWarning("In slotAccept");
    KConfig *config = KGlobal::config();
    config->setGroup("Print");
    config->writeEntry("Scale", scaleLarge->isChecked());
    config->writeEntry("Zoom", zoomSmall->isChecked());
    config->writeEntry("Dither", manualDither->isChecked());
    config->writeEntry("MetricType", metricBox->currentItem());

    config->writeEntry("LMargin", lEdit->text().toDouble());
    config->writeEntry("RMargin", rEdit->text().toDouble());
    config->writeEntry("TMargin", tEdit->text().toDouble());
    config->writeEntry("BMargin", bEdit->text().toDouble());
    config->sync();
    QDialog::accept();
}

ConvertDialog::ConvertDialog(QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    setCaption(i18n("Format List"));
    QGridLayout *layout = new QGridLayout(this, 1, 1, 5);
    QLabel *lbl = new QLabel(i18n("Convert to image format:"), this);
    layout->addMultiCellWidget(lbl, 1, 1, 0, 1);

    listView = new QListView(this);
    listView->addColumn(i18n("Format"));
    listView->addColumn(i18n("Description"));
    listView->setMinimumHeight(128);
    listView->setAllColumnsShowFocus(true);
    listView->setSorting(0, true);
    listView->setShowSortIndicator(true);
    listView->setShowToolTips(true);
    listView->setSelectionMode(QListView::Single);
    connect(listView, SIGNAL(clicked(QListViewItem *)), this,
            SLOT(slotFormatClicked(QListViewItem *)));
    connect(listView, SIGNAL(doubleClicked(QListViewItem *)), this,
            SLOT(slotFormatDoubleClicked(QListViewItem *)));

    // load up formats
    ExceptionInfo exception;
    GetExceptionInfo(&exception);
    const MagickInfo *i = GetMagickInfo(NULL, &exception);
    while(i){
        if(i->encoder && displayFormat(i->name))
            (void) new QListViewItem(listView, i->name, i->description);
        i = i->next;
    }
    listView->setResizeMode(QListView::LastColumn);
    DestroyExceptionInfo(&exception);
    layout->addMultiCellWidget(listView, 2, 2, 0, 1);

    lbl = new QLabel(i18n("Filename extension:"), this);
    lbl->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
    layout->addWidget(lbl, 3, 0);
    extEdit = new QLineEdit(this);
    extEdit->setFixedWidth(64);
    layout->addWidget(extEdit, 3, 1);
    layout->addMultiCellWidget(new KSeparator(Qt::Horizontal, this),
                               4, 4, 0, 1);

    KButtonBox *bbox = new KButtonBox(this);
    showAllBtn = bbox->addButton(i18n("Show All"));
    connect(showAllBtn, SIGNAL(clicked()), this, SLOT(slotShowAll()));
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(slotAccept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addMultiCellWidget(bbox, 5, 5, 0, 1);

    layout->setRowStretch(2, 1);
    layout->setColStretch(0, 1);

    // set a decent width
    resize(350, sizeHint().height());
}

void ConvertDialog::slotShowAll()
{
    listView->clear();
    ExceptionInfo exception;
    GetExceptionInfo(&exception);
    const MagickInfo *i = GetMagickInfo(NULL, &exception);
    while(i){
        if(i->encoder)
            (void) new QListViewItem(listView, i->name, i->description);
        i = i->next;
    }
    listView->setResizeMode(QListView::LastColumn);
    DestroyExceptionInfo(&exception);
    KMessageBox::information(this, i18n("You selected to view all formats. Some of these \
formats may only be valid for certain types of \
images, may display several kinds of the same \
format that is usually autodetected, or may make \
modifications such as reduced \
color depth. This is an advanced option and you are \
expected to know what you are doing."), i18n("Convert Warning"), "AdvancedConvert");
    showAllBtn->setEnabled(false);
}

void ConvertDialog::slotFormatClicked(QListViewItem *i)
{
    extEdit->setText(extensionForFormat(i->text(0).latin1()));
}

void ConvertDialog::slotFormatDoubleClicked(QListViewItem *i)
{
    extEdit->setText(extensionForFormat(i->text(0).latin1()));
    slotAccept();
}

void ConvertDialog::slotAccept()
{
    if(!listView->selectedItem()){
        QMessageBox::warning(this, i18n("Convert Error"),
                             i18n("You must select a format to convert to."));
    }
    else if(extEdit->text().isEmpty()){
        QMessageBox::warning(this, i18n("Convert Error"),
                             i18n("You must supply a filename extension\nfor this format."));

    }
    else
        accept();
}

QString ConvertDialog::extension()
{
    return(extEdit->text());
}

QString ConvertDialog::format()
{
    if(listView->selectedItem())
        return(listView->selectedItem()->text(0));
    return(QString::null);
}

// TODO - combine w/ convert dialog!
FormatDialog::FormatDialog(const QString &extStr, QWidget *parent,
                           const char *name)
    : QDialog(parent, name, true)
{
    setCaption(i18n("Format List"));
    QVBoxLayout *layout = new QVBoxLayout(this, 5, 5);
    QLabel *lbl = new QLabel(i18n("Could not determine format for %1.").arg(extStr), this);
    layout->addWidget(lbl);
    lbl = new QLabel(i18n("Please select one:"), this);
    layout->addWidget(lbl);

    listView = new QListView(this);
    listView->addColumn(i18n("Format"));
    listView->addColumn(i18n("Description"));
    listView->setMinimumHeight(128);
    listView->setAllColumnsShowFocus(true);
    listView->setSorting(0, true);
    listView->setShowSortIndicator(true);
    listView->setShowToolTips(true);
    listView->setSelectionMode(QListView::Single);
    connect(listView, SIGNAL(doubleClicked(QListViewItem *)), this,
            SLOT(slotFormatDoubleClicked(QListViewItem *)));

    // load up formats
    ExceptionInfo exception;
    GetExceptionInfo(&exception);
    const MagickInfo *i = GetMagickInfo(NULL, &exception);
    while(i){
        if(i->encoder && displayFormat(i->name))
            (void) new QListViewItem(listView, i->name, i->description);
        i = i->next;
    }
    listView->setResizeMode(QListView::LastColumn);
    DestroyExceptionInfo(&exception);
    layout->addWidget(listView, 1);

    layout->addWidget(new KSeparator(Qt::Horizontal, this));

    KButtonBox *bbox = new KButtonBox(this);
    showAllBtn = bbox->addButton(i18n("Show All"));
    connect(showAllBtn, SIGNAL(clicked()), this, SLOT(slotShowAll()));
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(slotAccept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addWidget(bbox);

    resize(350, sizeHint().height());
}

void FormatDialog::slotFormatDoubleClicked(QListViewItem *)
{
    slotAccept();
}

void FormatDialog::slotAccept()
{
    if(!listView->selectedItem()){
        QMessageBox::warning(this, i18n("Convert Error"),
                             i18n("You must select a format to convert to."));
    }
    else
        accept();
}

QString FormatDialog::format()
{
    if(listView->selectedItem())
        return(listView->selectedItem()->text(0));
    return(QString::null);
}

void FormatDialog::slotShowAll()
{
    listView->clear();
    ExceptionInfo exception;
    GetExceptionInfo(&exception);
    const MagickInfo *i = GetMagickInfo(NULL, &exception);
    while(i){
        if(i->encoder)
            (void) new QListViewItem(listView, i->name, i->description);
        i = i->next;
    }
    listView->setResizeMode(QListView::LastColumn);
    DestroyExceptionInfo(&exception);

    KMessageBox::information(this, i18n("You selected to view all formats. Some of these \
formats may only be valid for certain types of \
images, may display several kinds of the same \
format that is usually autodetected, or may make \
modifications such as reduced \
color depth. This is an advanced option and you are \
expected to know what you are doing."), i18n("Convert Warning"), "AdvancedConvert");
    showAllBtn->setEnabled(false);

}


#include "dialogs.moc"
