/*
 * 	    printer.cpp               (C) 2006-2008, Aurélien Croc (AP²C)
 *
 *  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; version 2 of the License.
 * 
 *  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, write to the
 *  Free Software Foundation, Inc.,
 *  59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 *  $Id: printer.cpp 298 2011-07-20 16:20:18Z tillkamppeter $
 * 
 */
#include "printer.h"
#include <time.h>
#include <string.h>
#include "errlog.h"
#include "request.h"
#include "ppdfile.h"



/*
 * Constructeur - Destructeur
 * Init - Uninit
 */
Printer::Printer()
{
    _manufacturer = NULL;
    _model = NULL;
    _beginPJL = NULL;
    _endPJL = NULL;
}

Printer::~Printer()
{
    if (_manufacturer)
        delete[] _manufacturer;
    if (_model)
        delete [] _model;
    if (_beginPJL)
        delete [] _beginPJL;
    if (_endPJL)
        delete [] _endPJL;
}



/*
 * Chargement des informations sur l'imprimante
 * Load the printer information
 */
bool Printer::loadInformation(const Request& request)
{
    const char *paperType, *paperSource;
    PPDValue value;

    // Get some printer information
    if (request.ppd()->get("BandSize", "QPDL").isNull()) {
        ERRORMSG(_("Unknown band size. Operation aborted."));
        return false;
    }
    _bandHeight = request.ppd()->get("BandSize", "QPDL");
    _packetSize = request.ppd()->get("PacketSize", "QPDL");
    _packetSize *= 1024;
    _manufacturer = request.ppd()->get("Manufacturer").deepCopy();
    _model = request.ppd()->get("ModelName").deepCopy();
    _color = request.ppd()->get("ColorDevice");
    _qpdlVersion = request.ppd()->get("QPDLVersion", "QPDL");
    if (!_qpdlVersion || (_qpdlVersion > 3 && _qpdlVersion != 5)) {
        ERRORMSG(_("Invalid QPDL version. Operation aborted."));
        return false;
    }
    value = request.ppd()->get("DocHeaderValues", "General");
    value.setPreformatted();
    if (value.isNull()) {
        ERRORMSG(_("Unknown header values. Operation aborted."));
        return false;
    }
    _unknownByte1 = ((const char *)value)[0];
    _unknownByte2 = ((const char *)value)[1];
    _unknownByte3 = ((const char *)value)[2];

    // Get PJL information
    value = request.ppd()->get("BeginPJL", "PJL");
    value.setPreformatted();
    if (value.isNull()) {
        ERRORMSG(_("No PJL header found. Operation aborted."));
        return false;
    }
    _beginPJL = value.deepCopy();
    value = request.ppd()->get("EndPJL", "PJL");
    value.setPreformatted();
    if (value.isNull()) {
        ERRORMSG(_("No PJL footer found. Operation aborted."));
        return false;
    }
    _endPJL = value.deepCopy();

    // Get the paper information
    paperType = request.ppd()->get("MediaSize");
    if (!paperType)
        paperType = request.ppd()->get("PageSize");
    if (!paperType) {
        ERRORMSG(_("Cannot get paper size information. Operation aborted."));
        return false;
    }
    if (!(strcasecmp(paperType, "Letter"))) _paperType = 0;
    else if (!(strcasecmp(paperType, "Legal"))) _paperType = 1;
    else if (!(strcasecmp(paperType, "A4"))) _paperType = 2;
    else if (!(strcasecmp(paperType, "Executive"))) _paperType = 3;
    else if (!(strcasecmp(paperType, "Ledger"))) _paperType = 4;
    else if (!(strcasecmp(paperType, "A3"))) _paperType = 5;
    else if (!(strcasecmp(paperType, "Env10"))) _paperType = 6;
    else if (!(strcasecmp(paperType, "Monarch"))) _paperType = 7;
    else if (!(strcasecmp(paperType, "C5"))) _paperType = 8;
    else if (!(strcasecmp(paperType, "DL"))) _paperType = 9;
    else if (!(strcasecmp(paperType, "B4"))) _paperType = 10;
    else if (!(strcasecmp(paperType, "B5"))) _paperType = 11;
    else if (!(strcasecmp(paperType, "EnvISOB5"))) _paperType = 12;
    else if (!(strcasecmp(paperType, "Postcard"))) _paperType = 14;
    else if (!(strcasecmp(paperType, "DoublePostcardRotated"))) _paperType = 15;
    else if (!(strcasecmp(paperType, "A5"))) _paperType = 16;
    else if (!(strcasecmp(paperType, "A6"))) _paperType = 17;
    else if (!(strcasecmp(paperType, "B6"))) _paperType = 18;
    else if (!(strcasecmp(paperType, "Custom"))) _paperType = 21;
    else if (!(strcasecmp(paperType, "C6"))) _paperType = 23;
    else if (!(strcasecmp(paperType, "Folio"))) _paperType = 24;
    else if (!(strcasecmp(paperType, "EnvPersonal"))) _paperType = 25;
    else if (!(strcasecmp(paperType, "Env9"))) _paperType = 26;
    else if (!(strcasecmp(paperType, "Oficio"))) _paperType = 28;
    else {
        ERRORMSG(_("Invalid paper size \"%s\". Operation aborted."), paperType);
        return false;
    }

    value = request.ppd()->getPageSize(paperType);
    if (value.width() == 0. || value.height() == 0.) {
        ERRORMSG(_("Null paper size \"%s\" found. Operation aborted."), 
            paperType);
        return false;
    }
    _pageWidth = value.width();
    _pageHeight = value.height();
    _hardMarginX = value.marginX();
    _hardMarginY = value.marginY();

    paperSource = request.ppd()->get("InputSlot");
    if (!paperSource) {
        paperSource = request.ppd()->get("DefaultInputSlot");
        if (!paperSource) {
            paperSource = "Auto";
            ERRORMSG(_("Cannot get input slot information."));
        }
    }
    if (!(strcasecmp(paperSource, "Auto"))) _paperSource = 1;
    else if (!(strcasecmp(paperSource, "Manual"))) _paperSource = 2;
    else if (!(strcasecmp(paperSource, "Multi"))) _paperSource = 3;
    else if (!(strcasecmp(paperSource, "Upper"))) _paperSource = 4;
    else if (!(strcasecmp(paperSource, "Lower"))) _paperSource = 5;
    else if (!(strcasecmp(paperSource, "Envelope"))) _paperSource = 6;
    else if (!(strcasecmp(paperSource, "Tray3"))) _paperSource = 7;
    else {
        ERRORMSG(_("Invalid paper source \"%s\". Operation aborted."), 
            paperSource);
        return false;
    }

    DEBUGMSG(_("%s printer %s with QPDL v. %lu"), _color ? "Color" : 
        "Monochrome", _model, _qpdlVersion);

    return true;
}

bool Printer::sendPJLHeader(const Request& request,
                         unsigned long    compression,
                         unsigned long    xResolution,
                         unsigned long    yResolution ) const
{
    const char *reverse;
    struct tm *timeinfo;
    time_t timestamp;

    time(&timestamp);
    timeinfo = localtime(&timestamp);

    printf("%s", _beginPJL);

    if (0x15 == compression) {
        printf("@PJL COMMENT USERNAME=\"Username: %s\"\n", request.userName());
        printf("@PJL COMMENT DOCNAME=\"%s\"\n", request.jobTitle());
        printf("@PJL JOB NAME=\"%s\"\n", request.jobTitle());
    }

    // Information about the job
    printf("@PJL DEFAULT SERVICEDATE=%04u%02u%02u\n", 1900+timeinfo->tm_year,
        timeinfo->tm_mon+1, timeinfo->tm_mday);
    printf("@PJL SET USERNAME=\"%s\"\n", request.userName());
    printf("@PJL SET JOBNAME=\"%s\"\n", request.jobTitle());

    if (0x15 == compression)
        printf("@PJL SET MULTIBINMODE=%s\n", "PRINTERDEFAULT");

   // Set some printer options
    if (!request.ppd()->get("EconoMode").isNull() && 
        request.ppd()->get("EconoMode") != "0")
        printf("@PJL SET ECONOMODE=%s\n", (const char *)request.ppd()->
                get("EconoMode"));
    if (!request.ppd()->get("PowerSave").isNull()) {
        if (request.ppd()->get("PowerSave") != "False") {
            printf("@PJL DEFAULT POWERSAVE=ON\n");
            printf("@PJL DEFAULT POWERSAVETIME=%s\n",
                (const char *)request.ppd()->get("PowerSave"));
        } else
            printf("@PJL DEFAULT POWERSAVE=OFF\n");
    }

    if (request.ppd()->get("JamRecovery").isTrue())
        printf("@PJL SET JAMRECOVERY=ON\n");
    else
        printf("@PJL SET JAMRECOVERY=OFF\n");
    if (request.printer()->color()) {
        if (!strcasecmp(request.ppd()->get("ColorModel"), "CMYK"))
            printf("@PJL SET COLORMODE=COLOR\n");
        else
            printf("@PJL SET COLORMODE=MONO\n");
    }

    if (0x15 == compression) {
        printf("@PJL SET RESOLUTION=%lu\n", yResolution);
        if ((600 == xResolution) && (600 == yResolution))
            printf("@PJL SET IMAGEQUALITY=0\n");
        if ((1200 == xResolution) && (600 == yResolution))
            printf("@PJL SET IMAGEQUALITY=1\n");
        printf("@PJL SET RGBCOLOR=%s\n", "STANDARD");
    }

    // Information about the duplex
    reverse = request.reverseDuplex() ? "REVERSE_" : "";
    switch (request.duplex()) {
        case Request::Simplex:
            printf("@PJL SET DUPLEX=OFF\n");
            break;
        case Request::LongEdge:
            printf("@PJL SET DUPLEX=ON\n");
            printf("@PJL SET BINDING=%sLONGEDGE\n", reverse);
            break;
        case Request::ShortEdge:
            printf("@PJL SET DUPLEX=ON\n");
            printf("@PJL SET BINDING=%sSHORTEDGE\n", reverse);
            break;
        case Request::ManualLongEdge:
            printf("@PJL SET DUPLEX=MANUAL\n");
            printf("@PJL SET BINDING=LONGEDGE\n");
            break;
        case Request::ManualShortEdge:
            printf("@PJL SET DUPLEX=MANUAL\n");
            printf("@PJL SET BINDING=SHORTEDGE\n");
            break;
    }
 
    // Set some job options
    if (request.ppd()->get("MediaType").isNull())
        printf("@PJL SET PAPERTYPE=OFF\n");
    else
        printf("@PJL SET PAPERTYPE=%s\n", (const char *)request.ppd()->
                get("MediaType"));
    if (request.ppd()->get("Altitude").isNull())
        printf("@PJL SET ALTITUDE=LOW\n");
    else
        printf("@PJL SET ALTITUDE=%s\n", (const char *)request.ppd()->
                get("Altitude"));
    if (request.ppd()->get("TonerDensity").isNull())
        printf("@PJL SET DENSITY=3\n");
    else
        printf("@PJL SET DENSITY=%s\n", (const char *)request.ppd()->
                get("TonerDensity"));
    if (request.ppd()->get("SRTMode").isNull())
        printf("@PJL SET RET=NORMAL\n");
    else
        printf("@PJL SET RET=%s\n", (const char *)request.ppd()->
                get("SRTMode"));

    if (0x15 == compression) {
        printf("@PJL SET BANNERSHEET=%s\n", "OFF");
        printf("@PJL SET TIMESTAMP=%s\n", "OFF");
    }

    printf("@PJL ENTER LANGUAGE = QPDL\n");
    fflush(stdout);

    return true;
}

bool Printer::sendPJLFooter(const Request& request) const
{
    printf("%s", _endPJL);
    fflush(stdout);

    return true;
}

/* vim: set expandtab tabstop=4 shiftwidth=4 smarttab tw=80 cin enc=utf8: */

