import("system.vars");
import("system.util");
import("system.datetime");
import("system.text");
import("system.neon");
import("system.db");
import("system.translate");
import("system.eMath");
import("Util_lib");
import("Sql_lib");
import("Keyword_lib");
import("Product_lib");
import("Report_lib");
import("OfferOrder_lib");
import("PostalAddress_lib");
import("Neon_lib");
import("KeywordRegistry_basic");
import("Address_lib");

/**
 * Methods used by Offer.
 * Do not create an instance of this!
 * 
 * @class
 */
function OfferUtils() {}
   
/**
 * Delivers the next valid offer number (has to be unique)
 * 
 * @return {String} next valid offer number
 */
OfferUtils.getNextOfferNumber = function() {
    return NumberSequencingUtils.getNextUniqueNumber("OFFERCODE", "OFFER");
}
    
/**
 * Delivers the next valid offer version number
 * 
 * @return {String} offerCode next valid offer version number
 */
OfferUtils.getNextOfferVersionNumber = function(offerCode) {
    return NumberSequencingUtils.getNextUniqueNumber("VERSNR", "OFFER", 1, "OFFERCODE = " + offerCode);
}
    
/**
 * Checks if the passed offer number is valid (has to be unique)
 * 
 * @param {String} offerNumber offer number to check
 * 
 * @return {Boolean} passed number is valid
 */
OfferUtils.validateOfferNumber = function(offerNumber) {
    return NumberSequencingUtils.validateUniqueNumber(offerNumber, "OFFERCODE", "OFFER");
}
    
OfferUtils.getOfferNumberValidationFailString = function() {
    return translate.text("The offer number already exists!");
}
    
OfferUtils.isEditable = function(status) {
    // TODO: Administrator darf immer �ndern, warten auf neue Berechtigungslogik?

    // Offer should be editable if offer state not equals "Sent", "Won" or "Lost"
    return status != "2" && status != "3" && status != "4";
}

/**
 * Create a new offer and open the offer context in NEW-mode
 */
OfferUtils.createNewOffer = function(pContextId, pRowId, pRelationId)
{
    var params = {};
    
    if (pRowId && pContextId)
    {
        params["ObjectRowId_param"] = pRowId;
        params["ObjectType_param"] = pContextId;
    }
    
    if (pRelationId)
        params["ContactId_param"] = pRelationId;
    
    neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params);
}

/*
 * Open Offer report, the report is translated to the language of the offer
 * 
 * @param {String} pOfferID
 *
 * @return {[]}
 */
OfferUtils.openOfferReport = function (pOfferID)
{    
    var offerReport = new Report("Offer_report");  
    
    var sqlUtil = new SqlMaskingUtils();
    
    var offerFields = [
        "ADDRESS", 
        "CONTACT_ID", 
        "LANGUAGE", 
        "PAYMENTTERMS", 
        "DELIVERYTERMS", //4
        "OFFERCODE", 
        "CURRENCY", 
        "OFFERDATE", 
        "HEADER", //8
        "VAT", 
        sqlUtil.isNull("VERSNR", "0"),
        sqlUtil.isNull("OFFERCODE", "0"), 
        "OBJECT_TYPE", //12
        "OBJECT_ROWID", //13
        "FOOTER" //14
    ];
   
    var offerSql = SqlCondition.begin()
        .andPrepare("OFFER.OFFERID", pOfferID)
        .buildSql("select " + offerFields.join(", ") + " from OFFER", "1 = 0");
    var offerData = db.array(db.ROW, offerSql);
    
    offerData[7] = datetime.toDate(offerData[7], translate.text("dd.MM.yyyy", language));
    
    var language = db.cell(SqlCondition.begin()
        .andPrepare("AB_LANGUAGE.ISO3", offerData[2])
        .buildSql("select ISO2 from AB_LANGUAGE", "1=0"));
    var contactId = offerData[1];
    
    
    var offerItemFields = [
        "OFFERITEM.INFO", 
        "OFFERITEM.ASSIGNEDTO",
        "OFFERITEM.PRODUCT_ID", 
        "OFFERITEM.ITEMNAME" , 
        "OFFERITEM.OPTIONAL",  //4
        "OFFERITEM.ITEMPOSITION", 
        "PRODUCT.PRODUCTCODE", 
        "PRODUCT.PRODUCTID", 
        "OFFERITEM.UNIT", //8
        sqlUtil.isNull("OFFERITEM.QUANTITY", "0"), 
        sqlUtil.isNull("OFFERITEM.PRICE", "0"),
        sqlUtil.isNull("OFFERITEM.DISCOUNT", "0"), 
        sqlUtil.isNull("OFFERITEM.VAT", "0"), //12
        "0", 
        "''"
    ]; 
    
    var offerItemSql = SqlCondition.begin()
        .andPrepare("OFFERITEM.OFFER_ID", pOfferID)
        .buildSql(
            "select " + offerItemFields.join(", ") + " from OFFERITEM left join PRODUCT on PRODUCT.PRODUCTID = OFFERITEM.PRODUCT_ID", 
            "1 = 0"
        );
    var itemData = db.table(offerItemSql);
    
    if (itemData.length == 0)
        return;
    
    var addrobj = new AddrObject(contactId);
    
    var fullPrice = 0;
    var itemSum = 0;
    var sumItemSum = 0;
    var total = 0;
    var sums = [];
    var vatsum = 0;
    var printDiscount = false;
    
    itemData = itemData.map(function (item)
    {
        //quantity * price
        fullPrice = eMath.mulDec(parseFloat(item[9]), parseFloat(item[10])); //price without discount
        
        if (item[4] != "1") //optional
        {
            //itemSum = (fullPrice * (100 - discount)) / 100
            itemSum = eMath.roundDec(eMath.divDec(eMath.mulDec(fullPrice, eMath.subDec(100, item[11])), 100), 2, eMath.ROUND_HALF_EVEN); //sum of the item (with discount)
            sumItemSum += itemSum; //total sum (without vat) 
        }
        //vatsum = itemSum * vat / 100
        vatsum = eMath.divDec(eMath.mulDec(itemSum, item[12]), 100); //vat per product
        if (item[12] > 0) 
            sums.push([item[12], vatsum]); //MWSteuerwerte für Map vorbereiten
        
        // sumItemSum + vat
        total = eMath.addDec(sumItemSum, offerData[9]); //total sum with vat
        
        if (!printDiscount && item[11] > 0)
            printDiscount = true;
        
        return [
            offerData[6],   //currency
            offerData[7],   //offerdate
            pOfferID,       //offerId
            item[0],        //info
            item[1],        //assignedTo
            item[3],        //itemname
            item[4],        //optional
            item[5],        //itemposition
            item[6],        //productcode
            offerData[8],   //header 
            offerData[14],   //footer 
            text.formatDouble(item[9], translate.text("#,##0"), true),          //quantity
            text.formatDouble(item[10], translate.text("#,##0.00"), true),      //price
            text.formatDouble(item[11], translate.text("0.00"), true),          //discount
            offerData[10],  //versnr
            offerData[5],   //offercode
            text.formatDouble(item[12], translate.text("#,##0.00"), true),      //vat
            text.formatDouble(itemSum, translate.text("#,##0.00"), true),       //itemsum
            KeywordUtils.getViewValue($KeywordRegistry.quantityUnit(), item[8]) //unittext
        ];
    });
    
    // TODO: get Images implementieren
    var imgData = ["meineFirma | Konrad-Zuse-Straße 4  |  DE 84144 Geisenhausen",
                   "base64:iVBORw0KGgoAAAANSUhEUgAAAM4AAABRCAYAAACaL5lSAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNS4xIFdpbmRvd3MiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MDA4QzAyM0IwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MDA4QzAyM0MwREIwMTFFNEFGMDREM0VEMjExRjlBRTIiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowMDhDMDIzOTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDowMDhDMDIzQTBEQjAxMUU0QUYwNEQzRUQyMTFGOUFFMiIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PhF3nYoAAAlvSURBVHja7J1fjBXV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"]
                // getMyASYS_ICONSdata();
    
    // TODO: implementieren wenn Attribute möglich sind
    var adma = ""; //adma = Aussendienstmitarbeiter
    /*var adm = getAddressData( [GetAttributeKey( "Aussendienst", "1", orgrelid, pUser )[0]],
        [["Person","function", "concat( ['SALUTATION', 'TITLE', 'FIRSTNAME','LASTNAME'])"],
        ["Telefon", "function", "getCommAddrSQL('Telefon', 'CONTACT.CONTACTID')"],
        ["Email", "function", "getCommAddrSQL('E-Mail', 'CONTACT.CONTACTID')"]
        ] );
    var adma = "";
    if (adm[1] != undefined)  adma = adm[1].join("\n");*/
    
    var params = {
        "PaymentConditions" : translate.text("Conditions of payment", language),
        "Articledescription" : translate.text("Articledescription", language),
        "DeliveryConditions" : translate.text("Deliveryspecification", language),
        "OFFERPers" : addrobj.getFormattedAddress(false, "{letter_salutation},"), 
        "Articlenumber" : translate.text("Articlenumber", language),
        "OFFERAddr" : translate.text(offerData[0].trim(), language),
        "PlusSalestax" : translate.text("Plus Salestax", language),
        "Unitprice" : translate.text("Unitprice", language),
        "directlyResponsible" : translate.text("Directly responsible:", language),
        "Number" : translate.text("Number", language),
        "Discount" : translate.text("Discount", language),
        "Amount" : translate.text("Amount", language),
        "Total" : translate.text("Total", language),
        "Date" : translate.text("Date", language),
        "VAT" : translate.text("VAT", language),
        "Sum" : translate.text("Sum", language),
        "Pos" : translate.text("Pos.", language),
        "myAddr" : imgData[0],
        "OfferPaymentTerm" : KeywordUtils.getViewValue($KeywordRegistry.paymentTerm(), offerData[3]),
        "OfferDeliveryTerm" : KeywordUtils.getViewValue($KeywordRegistry.deliveryTerm(), offerData[4]),
        "responsible" : adma,
        "SUMITEMSUM" : sumItemSum,
        "TOTAL" : text.formatDouble(total, translate.text("#,##0.00"), true),
        "printDiscount" : printDiscount ? "1" : "0"
    };
    
    

    offerReport.addImage("myLogo", imgData[1]);

    offerReport.addSubReportData("subdata", ReportData.begin(["VAT","WERT"]).add(sums));
    offerReport.addReportParams(params);

    offerReport.setReportData(ReportData.begin(
        [
            "OFFER_CURRENCY", 
            "OFFER_OFFERDATE", 
            "OFFER_OFFERID",  
            "OFFERITEM_INFO", 
            "OFFERITEM_ASSIGNEDTO", //4
            "OFFERITEM_ITEMNAME" , 
            "OFFERITEM_OPTIONAL", 
            "OFFERITEM_ITEMPOSITION", 
            "PRODUCT_PRODUCTCODE", //8
            "OFFER_HEADER", 
            "OFFER_FOOTER", 
            "OFFERITEM_QUANTITY", 
            "OFFERITEM_PRICE", 
            "OFFERITEM_DISCOUNT", //13
            "OFFER_VERSNR", 
            "OFFER_OFFERCODE", 
            "OFFERITEM_VAT", 
            "ITEMSUM", // 17
            "OFFERITEM_UNITTEXT"
        ])
        .add(itemData));
    offerReport.openReport();
}

/**
 * opens an offer in NEW mode with values from an offer
 * 
 * @param {String} pOfferId of the offer
 * @param {String} pContactId
 * @param {String} pLanguage
 * @param {String} [pCurrency=""]
 * @param {String} [pHeader=""]
 * @param {String} [pFooter=""]
 * @param {String} [pDeliveryTerm=""]
 * @param {String} [pPaymentTerm=""]
 * @param {String} [pSalesprojectId=""]
 */
OfferUtils.copyOffer = function (pOfferId, pContactId, pLanguage, pCurrency, pHeader, pFooter, pDeliveryTerm, pPaymentTerm, pObjectType, pRowId)
{
    var params = {
        "ContactId_param" : pContactId,
        "OfferLanguage_param" : pLanguage,
        "OfferOriginal_Id_param" : pOfferId,
        "OfferCurrency_param" : pCurrency || "",
        "OfferHeader_param" : pHeader || "",
        "OfferFooter_param" : pFooter || "",
        "OfferDeliveryTerm_param" : pDeliveryTerm || "",
        "OfferPaymentTerm_param" : pPaymentTerm || "",
        "ObjectType_param" : pObjectType || "",
        "ObjectRowId_param" : pRowId || ""
    };
    neon.openContext("Offer", null, null, neon.OPERATINGSTATE_NEW, params);
}

/**
 * copies all offerItems from one offer to another
 * 
 * @param {String} pSourceOfferId
 * @param {String} pTargetOfferId
 */
OfferUtils.copyOfferItems = function (pSourceOfferId, pTargetOfferId)
{
    var InputMapping = {
        "OFFERITEM": {
            condition: "OFFER_ID = '" + pSourceOfferId + "' order by ITEMSORT",
            ValueMapping: {
                "OFFER_ID" : pTargetOfferId
            }
        }
    };
    CopyModuleUtils.copyModule(InputMapping);
    
    var oiUtils = new OfferItemUtils(pTargetOfferId);
    
    //update order price
    cols = ["NET", "VAT"];
    var vals = oiUtils.getNetAndVat();
    
    db.updateData("OFFER", cols, null, vals, SqlCondition.equals("OFFER.OFFERID", pTargetOfferId, "1 = 2"));
}

/**
 * opens an order in NEW mode with values from an offer
 * 
 * @param pOfferId {String} id of the offer
 * @param pSalesprojectId {String} salesproject id
 * @param pContactId {String} contact id
 * @param pLanguage {String} language
 * @param pCurrency {String} [currency=""]
 * @param pAddress {String} [address=""]
 * @param pHeader {String} [header=""]
 */
OfferUtils.copyToOrder = function (pOfferId, pSalesprojectId, pContactId, pLanguage, pCurrency, pAddress, pHeader)
{
    var params = {
        "ContactId_param" : pContactId,
        "SalesprojectId_param" : pSalesprojectId,
        "OrderLanguage_param" : pLanguage,
        "OfferId_param" : pOfferId,
        "OrderCurrency_param" : pCurrency || "",
        "OrderAddress_param" : pAddress || "",
        "OrderHeader_param" : pHeader || ""
    };
    neon.openContext("Order", null, null, neon.OPERATINGSTATE_NEW, params);
}

/**
 * gets the title of an offer from the id
 * 
 * @param pOfferId {String} offer-id
 * 
 * @return {String} offer title 
 */
OfferUtils.getOfferTitleById = function (pOfferId)
{
    if (!pOfferId)
        return "";
    var offerNumber = db.array(db.ROW, SqlCondition.begin()
        .andPrepare("OFFER.OFFERID", pOfferId)
        .buildSql("select OFFERCODE, VERSNR from OFFER"));
    return offerNumber.length > 0 
        ? translate.text("Offer") + " " + offerNumber.join("-") 
        : "";
}


/******************************************************************************/

/**
 * Provides methods for dealing with offer items.
 * Inherits methods from abstract class ItemUtils.
 * For documentation, see class ItemUtils.
 * 
 * @class
 */
function OfferItemUtils(pOfferId) {
    // extends ItemUtils
    ItemUtils.apply(this, [pOfferId, "OFFER"]);
    OfferItemUtils.prototype = Object.create(ItemUtils.prototype);
    OfferItemUtils.prototype.constructor = OfferItemUtils;
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.getNetAndVat = function(offeritemIdsToDel) {
    return ItemUtils.prototype.getNetAndVat.apply(this, [offeritemIdsToDel]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.initItemTree = function() {
    ItemUtils.prototype.initItemTree.apply(this);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.getItemSum = function(pQuantity, pPrice, pDiscount, pOptional) {
    return ItemUtils.prototype.getItemSum.apply(this, [pQuantity, pPrice, pDiscount, pOptional]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.getItemVAT = function(pQuantity, pPrice, pDiscount, pVAT, pOptional) {
    return ItemUtils.prototype.getItemVAT.apply(this, [pQuantity, pPrice, pDiscount, pVAT, pOptional]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.roundPrice = function(pPrice) {
    return ItemUtils.prototype.roundPrice.apply(this, [pPrice]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.insertPartsList = function(pProductId, pAssignedTo, pCurrency, pContactId) {
    this.initItemTree();
    
    var cols =  ["OFFERITEMID"
                , "OFFER_ID"
                , "PRODUCT_ID"
                , "GROUPCODEID"
                , "ASSIGNEDTO"
                , "ITEMNAME"
                , "UNIT"
                , "PRICE"
                , "VAT"
                , "QUANTITY"
                , "OPTIONAL"
                , "ITEMPOSITION"
                , "ITEMSORT"];

    return ItemUtils.prototype.insertPartsList.apply(this, [cols, pProductId, pAssignedTo, pCurrency, pContactId, [["INFO", "INFO"]]]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.deletePartsList = function(pItemId) {
    this.initItemTree();
    
    return ItemUtils.prototype.deletePartsList.apply(this, [pItemId]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.getNextItemSort = function(pIds) {
    this.initItemTree();

    return ItemUtils.prototype.getNextItemSort.apply(this, [pIds]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.getNextItemPosition = function(pAssignedTo, pTree, pIds) {
    this.initItemTree();

    return ItemUtils.prototype.getNextItemPosition.apply(this, [pAssignedTo, pTree, pIds]);
}

/**
 * For documentation, see class ItemUtils.
 */
OfferItemUtils.prototype.reOrgItems = function() {
    this.initItemTree();
    
    ItemUtils.prototype.reOrgItems.apply(this);
}