// ************************************************************************************************************
// Author: Marcin Załęczny
// Release Date: 2010-11-08
// Licence: The GNU Lesser General Public License, version 3.0 (LGPLv3)
// ************************************************************************************************************
#include "mzXpsPrintTicket.h"

CXpsPrintTicket::CXpsPrintTicket(CString xmlVersion, CString xmlEncoding)
    : CXmlDocument(L"PrintTicket", L"psf", xmlVersion, xmlEncoding)
{
    this->setRealClassName(L"CXpsPrintTicket");
}

CXpsPrintTicket::~CXpsPrintTicket() {
}

VOID CXpsPrintTicket::addPsfXmlns() {
    this->addXmlns(L"http://schemas.microsoft.com/windows/2003/08/printing/printschemaframework", L"psf");
}

VOID CXpsPrintTicket::addXsiXmlns() {
    this->addXmlns(L"http://www.w3.org/2001/XMLSchema-instance", L"xsi");
}

VOID CXpsPrintTicket::addXsdXmlns() {
    this->addXmlns(L"http://www.w3.org/2001/XMLSchema", L"xsd");
}

VOID CXpsPrintTicket::addNs0000Xmlns() {
    this->addXmlns(L"http://schemas.microsoft.com/windows/2006/06/printing/printschemakeywords/microsoftxpsdocumentwriter", L"ns0000");
}

VOID CXpsPrintTicket::addPskXmlns() {
    this->addXmlns(L"http://schemas.microsoft.com/windows/2003/08/printing/printschemakeywords", L"psk");
}

CXmlNode* CXpsPrintTicket::createParameter(CXmlNode* parentNode, CString parameterTag, CString paramName, CString paramValue) {
    // Not implemented yet. Here we add checking name of parameter and automatic guessing (based on microsoft schemas)
    // proper paramType and paramNS
    return NULL;
}

CXmlNode* CXpsPrintTicket::createParameter(CXmlNode* parentNode, CString parameterTag, CString paramName, CString paramValue, CString paramType, CString paramNS) {
    CXmlNode* param_Node = new CXmlNode(parameterTag, L"psf", parentNode);
    if (param_Node) {
        CString pname(paramName);
        if (paramNS != COMMON_EMPTY_STRING) {
            pname.prepend(paramNS + L":");
        }
        param_Node->addAttribute(L"name", pname);
        this->_createValueNode(param_Node, paramValue, paramType);
        if (parentNode) {
            parentNode->addChild(param_Node);
        }
        return param_Node;
    }
    
    return NULL;
}

CXmlNode* CXpsPrintTicket::createParameterInit(CXmlNode* parentNode, CString paramName, CString paramValue, CString paramType, CString paramNS) {
    return this->createParameter(parentNode, L"ParameterInit", paramName, paramValue, paramType, paramNS);
}

CXmlNode* CXpsPrintTicket::createScoredProperty(CXmlNode* parentNode, CString propertyName, CString propertyValue, CString propertyType, CString propertyNS) {
    return this->createParameter(parentNode, L"ScoredProperty", propertyName, propertyValue, propertyType, propertyNS);
}

CXmlNode* CXpsPrintTicket::createFeature(CXmlNode* parentNode, CString featureName, CString featureNS) {
    CXmlNode* feature_Node = new CXmlNode(L"Feature", L"psf", parentNode);
    if (feature_Node) {
        CString fname(featureName);
        if (featureNS != COMMON_EMPTY_STRING) {
            fname.prepend(featureNS + L":");
        }
        feature_Node->addAttribute(L"name", fname);
        if (parentNode) {
            parentNode->addChild(feature_Node);
        }
        
        return feature_Node;
    }
    
    return NULL;
}

CXmlNode* CXpsPrintTicket::createFeatureWithOption(CXmlNode* parentNode, CString featureName, CString featureNS, CString optionName, CString optionNS) {
    CXmlNode* featureNode = this->createFeature(parentNode, featureName, featureNS);
    if (featureNode) {
        CString oname(optionName);
        if (optionNS != COMMON_EMPTY_STRING) {
            oname.prepend(optionNS + L":");
        }
        CXmlNode* optionNode = new CXmlNode(L"Option", L"psf", featureNode);
        if (optionNode) {
            if (optionNS != COMMON_EMPTY_STRING) {
                optionName.prepend(optionNS + L":");
            }
            optionNode->addAttribute(L"name", optionName);
            featureNode->addChild(optionNode);
        }
        
        return featureNode;
    }
    
    return NULL;
}

VOID CXpsPrintTicket::setFeatureOptionScoredProperty(CXmlNode* featureNode, CString optionName, CString optionNS, CString scoredPropertyName, CString scoredPropertyValue, CString scoredPropertyNS, CString scoredPropertyType) {
    if (featureNode) {
        CString oname(optionName);
        if (optionNS != COMMON_EMPTY_STRING) {
            oname.prepend(optionNS + L":");
        }
        CXmlNode* option_Subnode = featureNode->getFirstChildWithAttrib(L"Option", L"psf", L"name", COMMON_EMPTY_STRING, oname);
        if (!option_Subnode) {
            option_Subnode = new CXmlNode(L"Option", L"psf", featureNode);
            if (option_Subnode) {
                option_Subnode->addAttribute(L"name", oname);
            }
            featureNode->addChild(option_Subnode);
        }
        
        if (option_Subnode) {
            CString spname(scoredPropertyName);
            if (scoredPropertyNS != COMMON_EMPTY_STRING) {
                spname.prepend(scoredPropertyNS + L":");
            }
            CXmlNode* scoredProperty_Subnode = option_Subnode->getFirstChildWithAttrib(L"ScoredProperty", L"psf", L"name", COMMON_EMPTY_STRING, spname);
            if (!scoredProperty_Subnode) {
                this->createScoredProperty(option_Subnode, scoredPropertyName, scoredPropertyValue, scoredPropertyType, scoredPropertyNS);
            } else {
                CXmlNode* value_Subnode = scoredProperty_Subnode->getFirstChild();
                if (!value_Subnode) {
                    this->_createValueNode(scoredProperty_Subnode, scoredPropertyValue, scoredPropertyType);
                } else {
                    CXmlNode* text_Subnode = value_Subnode->getFirstChild();
                    if (!text_Subnode) {
                        value_Subnode->addTextChild(scoredPropertyValue);
                    } else {
                        value_Subnode->setAttribute(L"text", scoredPropertyValue, L"");
                    }
                }
            }
        }
    }
}

CXmlNode* CXpsPrintTicket::createPageMediaSizeFeature(CXmlNode* parentNode, CString PageMediaSize, CString MediaSizeWidth, CString MediaSizeHeight) {
    CXmlNode* feature;
    feature = this->createFeature(NULL, L"PageMediaSize", L"psk");
    this->setFeatureOptionScoredProperty(feature, PageMediaSize, L"psk", L"MediaSizeWidth", MediaSizeWidth, L"psk", L"integer");
    this->setFeatureOptionScoredProperty(feature, PageMediaSize, L"psk", L"MediaSizeHeight", MediaSizeHeight, L"psk", L"integer");
    if (parentNode) {
        parentNode->addChild(feature);
    }
    return feature;
}

CXmlNode* CXpsPrintTicket::createPageOutputColorFeature(CXmlNode* parentNode, INT DeviceBitsPerPixel, INT DriverBitsPerPixel) {
    CXmlNode* feature;
    feature = this->createFeature(NULL, L"PageOutputColor", L"psk");
    this->setFeatureOptionScoredProperty(feature, L"Color", L"psk", L"DeviceBitsPerPixel", DeviceBitsPerPixel, L"psk", L"integer");
    this->setFeatureOptionScoredProperty(feature, L"Color", L"psk", L"DriverBitsPerPixel", DriverBitsPerPixel, L"psk", L"integer");
    if (parentNode) {
        parentNode->addChild(feature);
    }
    return feature;
}

CXmlNode* CXpsPrintTicket::createResolutionFeature(CXmlNode* parentNode, CString PageResolutionX, CString PageResolutionY) {
    CXmlNode* feature;
    // default to A4 settings
    feature = this->createFeature(NULL, L"PageResolution", L"psk");
    this->setFeatureOptionScoredProperty(feature, L"Option1", L"ns0000", L"ResolutionX", PageResolutionX, L"psk", L"integer");
    this->setFeatureOptionScoredProperty(feature, L"Option1", L"ns0000", L"ResolutionY", PageResolutionY, L"psk", L"integer");
    if (parentNode) {
        parentNode->addChild(feature);
    }
    return feature;
}
    
CXmlNode* CXpsPrintTicket::_createValueNode(CXmlNode* parentNode, CString value, CString type) {
    CXmlNode* value_Node = new CXmlNode(L"Value", L"psf", parentNode);
    if (value_Node) {
        value_Node->addTextChild(value);
        if (type != COMMON_EMPTY_STRING) {
            CString ptype(type);
            if (!ptype.startsWith(L"xsd:")) {
                ptype.prepend(L"xsd:");
            }
            value_Node->addAttribute(L"type", ptype, L"xsi");
        }
        
        if (parentNode) {
            parentNode->addChild(value_Node);
        }
    }
    
    return value_Node;
}
