﻿var PrintingMethods = { "Digital": 0, "Traditional": 1 };
var Sides = { "None": 0, "Front": 1, "Back": 2, "Both": 3 };

function Postcard(PM) {
    this.PrintingMethod = null;
    this.Size = null;
    this.Quantity = null;
    this.LogoRemoval = null;
    this.MailingServices = null;
    this.DesignServices = null;
    this.Proof = null;
    this.Finishing = null;
    this.TextRemoval = null;
    this.Stock = null;
    this.HiGloss = null;
    this.VariableData = null;
    this.RoundCorner = null;

    if (arguments.length > 0)
        this.PrintingMethod = PM;

    this.SizeType = function(h, w) {
        this.height = h;
        this.width = w;
    }

    this.SizeNameToSize = function(name) {
        var sizeName = '';
        switch (name.toLowerCase()) {
            case "business card": sizeName = '2x3.5'; break;
            case "bookmark": sizeName = '2x6'; break;
            default: sizeName = name;
        }
        var splitArray = sizeName.split('x');

        var h = Math.min(splitArray[0], splitArray[1]);
        var w = Math.max(splitArray[0], splitArray[1]);

        var size = new this.SizeType(h, w);
        return size;
    }

    this.GetPrintingMethod = function(Quantity) {
        if (Quantity < 1000)
            return PrintingMethods.Digital;
        else
            return PrintingMethods.Traditional;
    }

    this.Price = function(Size, Quantity, PrintMeth, Turnaround, Proof, Stock) {
        var p = this.PrintFees(Size, Quantity, PrintMeth);
        if (p > 0) {
            var of = this.OptionsFees(Size, Quantity, p);
            p += of;
        }

        if ((typeof discpct != 'undefined') && (typeof disccap != 'undefined')) {
            var disc = Math.min(p * discpct, disccap);
            p = p - disc;
        }
        if ((arguments.length > 3) && (Turnaround != null))
            p = p + this.TurnaroundFee(p, Turnaround);

        if ((arguments.length > 4) && (Proof != null))
            p = p + this.ProofFee(Proof);

        if ((arguments.length > 5) && (Stock != null)) {
            var sz = this.SizeNameToSize(Size);
            var numberUp = this.NumberPerSheet(19.5, 13.5, 0.125, sz.width, sz.height);
            if (numberUp > 0) {
                sheetsNeeded = this.SheetsNeeded(Quantity, numberUp);
                p = p + this.StockFee(Stock, sheetsNeeded);
            }
        }

        return Math.ceil(p);
    }

    this.PrintFees = function(Size, Quantity, PrintMeth) {
        // Size: in the format '4x6', 'bookmark', etc.,
        // PrintMeth is optional
        var pm; // printing method
        var sz; // size
        if (arguments.length < 3)
            pm = this.GetPrintingMethod(Quantity);
        else
            pm = PrintMeth;
        sz = this.SizeNameToSize(Size); // convert Size to numeric if necessary
        try {
            Quantity = parseInt(Quantity);
        }
        catch (e) {
            return 0;
        }
        if (Quantity <= 0) {
            return 0;
        }
        switch (pm) {
            case PrintingMethods.Traditional: temp = this.OffsetPrintingFees(Math.max(Quantity,1000), sz.height, sz.width); break;
            case PrintingMethods.Digital:
                if ((typeof insanePrices != "undefined") && (insanePrices == true))
                    temp = this.InsaneDigitalPrintingFees(Quantity, sz.height, sz.width);
                else
                    temp = this.DigitalPrintingFees(Quantity, sz.height, sz.width);
                break;
            default: temp = 0;
        }

        var bc_price;
        switch (pm) {
            case PrintingMethods.Traditional: bc_price = this.OffsetPrintingFees(Math.max(Quantity, 1000), 2, 3.5); break;
                
            case PrintingMethods.Digital:
                if ((typeof insanePrices != "undefined") && (insanePrices == true))
                    bc_price = this.InsaneDigitalPrintingFees(Quantity, 2, 3.5);
                else
                    bc_price = this.DigitalPrintingFees(Quantity, 2, 3.5);
                break;
            default: bc_price = 0;
        }

        if (temp > 0) {
            temp = Math.max(bc_price, temp);

            temp = Math.ceil(temp);
        }
        return temp;
    }

    this.OffsetDiscount = function(Quantity) {
        var rate = 0;
        if (Quantity < 1000)
            rate = 0.5;
        else
            if ((Quantity >= 1000) && (Quantity < 2000))
            rate = 0.4;
        else
            if ((Quantity >= 2000) && (Quantity < 3000))
            rate = 0.3;
        else
            if ((Quantity >= 3000) && (Quantity < 4000))
            rate = 0.2;
        else
            if ((Quantity >= 4000) && (Quantity < 5000))
            rate = 0.1;
        return rate;
    }

    this.OffsetPrintingFees = function(Quantity, Size1, Size2) {
        var tempPrice = 0;
        if ((Size1 < 1.5) || (Size1 > 27) || (Size2 < 1.5) || (Size2 > 39)) {
            return 0;
        }
        tempPrice = this.TwelvePointPriceFromTable(Quantity, Size1, Size2);

        if (tempPrice != 0)
            return tempPrice;
        else {
            return this.OffsetPostcardPriceFromArea(Quantity, Size1, Size2);
        }
    }

    this.InsaneDigitalPrintingFees = function(Quantity, Size1, Size2) {
        return this.InsaneDigitalPriceFromArea(Quantity, Size1, Size2);
    }

    this.DigitalPrintingFees = function(Quantity, Size1, Size2) {
        tempPrice = 0;
        if ((Size1 < 1.5) || (Size1 > 13.5) || (Size2 < 1.5) || (Size2 > 19.5)) {
            //alert('over');
            return -1;
        }
        //        if ((tempPrice = this.DigitalPriceFromTable(Quantity, Size1, Size2)) > 0)
        //            return tempPrice;
        //        else
        return this.DigitalPriceFromArea(Quantity, Size1, Size2);
    }

    this.TwelvePointPriceFromTable = function(Quantity, Size1, Size2) {
        qtyNames = [1000, 2500, 5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000, 45000, 50000];
        return this.OffsetPriceFromTable(Quantity, Size1, Size2, qtyNames);
    }

    this.TenPointPriceFromTable = function(Quantity, Size1, Size2) {
        qtyNames = [0, 5000, 10000, 15000, 20000, 25000, 30000, 35000, 40000, 45000, 50000]; // Zero skips a row
        return this.OffsetPriceFromTable(Quantity, Size1, Size2, qtyNames);
    }

    this.StickerPriceFromTable = function(Quantity, Size1, Size2) {
        qtyNames = [0, 2000, 4000, 6000, 8000, 10000, 12000, 14000, 16000, 18000, 20000]; // Zero skips a row
        return this.OffsetPriceFromTable(Quantity, Size1, Size2, qtyNames);
    }

    this.SizeNameToArea = function(SizeName) {
        size = SizeNameToSize(SizeName);
        try {
            tempArea = parseFloat(size.height) * parseFloat(size.width);
            return tempArea;
        }
        catch (e) {
            return 0;
        }
    }

    this.ClosestOffsetSize = function(Size1, Size2) {
        var sizeNames = ["2x3.5", "2x6", "3.5x5.5", "4x6", "4.25x6", "4x9", "5x7", "6x8", "7x10", "8.5x11"];
        var surfaceArea = (Size1 * Size2);
        i = 0;
        closestFound = false;

        while ((i <= (sizeNames.length)) && !closestFound) {
            areaNow = SizeNameToArea(sizeNames[i]);
            areaNext = SizeNameToArea(sizeNames[i + 1]);
            if ((areaNow == 0) || (areaNext == 0))
                return "";
            closestFound = Math.abs(surfaceArea - areaNow) < Math.abs(surfaceArea - areaNext);
            i++;
        }
        if (closestFound) {
            return sizeNames[i - 1];

        }
        else {
            return sizeNames[sizeNames.length - 1]; // return the last element in the array
        }
    }

    this.OffsetPriceFromTable = function(Quantity, Size1, Size2, QuantityNames) {
        sizeNames = ["2x3.5", "2x6", "3.5x5.5", "4x6", "4.25x6", "4x9", "5x7", "6x8", "7x10", "8.5x11"];
        priceArray = 
                    [[79, 89, 149, 149, 149, 239, 239, 289, 419, 559], // 1000
                    [109, 119, 199, 199, 199, 319, 319, 379, 559, 749], // 2500
					[129, 149, 249, 249, 249, 399, 399, 479, 699, 929], // 5000
					[209, 239, 399, 399, 399, 639, 639, 769, 1119, 1489], // 10000
					[289, 329, 549, 549, 549, 879, 879, 1059, 1539, 2049], // 15000
					[369, 419, 699, 699, 699, 1119, 1119, 1349, 1959, 2609], // 20000
					[449, 509, 849, 849, 849, 1359, 1359, 1629, 2379, 3159], // 25000
					[529, 599, 999, 999, 999, 1599, 1599, 1919, 2799, 3719], // 30000
					[609, 689, 1149, 1149, 1149, 1839, 1839, 2209, 3219, 4279], // 35000
					[689, 779, 1299, 1299, 1299, 2079, 2079, 2499, 3639, 4839], // 40000
					[769, 869, 1449, 1449, 1449, 2319, 2319, 2779, 4059, 5389], // 45000
					[849, 959, 1599, 1599, 1599, 2559, 2559, 3069, 4479, 5949]]; // 50000

        return this.PriceFromTable(Quantity, Size1, Size2, QuantityNames, sizeNames, priceArray);
    }

    this.DigitalPriceFromTable = function(Quantity, Size1, Size2) {
        sizeNames = ["2x3.5", "2x6", "3.5x5.5", "4x6", "4.25x6", "5x7", "5.5x8.5", "6x9", "8.5x11", "11x17"];
        quantityNames = [100, 200, 300, 400, 500];
        priceArray = [[89, 99, 109, 109, 109, 129, 129, 129, 169, 259],
				        [99, 109, 129, 129, 129, 179, 179, 179, 259, 429],
				        [109, 119, 149, 159, 159, 229, 229, 229, 349, 609],
				        [119, 129, 169, 179, 179, 279, 279, 279, 429, 779],
				        [129, 139, 189, 209, 209, 329, 329, 329, 519, 949]];

        if ((Size1 >= 5) && (Size1 <= 6) && (Size2 >= 7) && (Size2 <= 9)) {
            Size1 = 5;
            Size2 = 7;
        }
        return this.PriceFromTable(Quantity, Size1, Size2, quantityNames, sizeNames, priceArray);
    }  // DigitalPriceFromTable

    this.PriceFromTable = function(Quantity, Size1, Size2, QuantityNames, SizeNames, PriceArray) {

        sizeName = Size1 + "x" + Size2;

        sizeFound = false;
        col = 0;

        while (!(sizeFound = (SizeNames[col] == sizeName)) && (col < SizeNames.length - 1))
            col++;
        if (!sizeFound)
            return 0;
        else {
            row = 0;
            while (!(qtyFound = (QuantityNames[row] == Quantity)) && (row < QuantityNames.length - 1))
                row++;

            if (qtyFound) {
                return PriceArray[row][col];
            }
            else
                return 0;
        } // else (size was found)
    }

    this.OffsetPostcardPriceFromArea = function(Quantity, Size1, Size2) {

        // Calculates print price based on surface area, $149 minimum
        minimumPrice = 149;

        price5000 = 11 * Size1 * Size2; // ...is $13 per sq. inch

        tempPrice = price5000 * (1 + (0.6 * ((Quantity / 5000) - 1)));

        if (tempPrice < minimumPrice)
            tempPrice = minimumPrice;

        return tempPrice;
    }

    this.OffsetStickerPriceFromArea = function(Quantity, Size1, Size2) {

        // Calculates print price based on surface area, $149 minimum
        minimumPrice = 149;

        price2000 = 11 * Size1 * Size2; // ...is $13 per sq. inch

        tempPrice = price2000 * (1 + (0.6 * ((Quantity / 2000) - 1)));

        if (tempPrice < minimumPrice)
            tempPrice = minimumPrice;

        return tempPrice;
    }

    this.IsStandardBusCard = function(Size1, Size2) {
        if (((Size1 == 2) && (Size2 == 3.5)) || ((Size1 == 3.5) && (Size2 == 2)))
            return true;
        else return false;
    }

    this.NumberPerSheet = function(SheetSize1, SheetSize2, Gutter, Size1, Size2) {
        if (this.IsStandardBusCard(Size1, Size2))
            return 24;

        if ((Size1 == 0) || (Size2 == 0))
            return 0;
        var numberUp;
        x = parseInt(Math.floor(SheetSize1 / (Size1 + Gutter)));
        y = parseInt(Math.floor(SheetSize2 / (Size2 + Gutter)));
        xr = parseInt(Math.floor(SheetSize1 / (Size2 + Gutter)));
        yr = parseInt(Math.floor(SheetSize2 / (Size1 + Gutter)));

        if ((x * y) >= (xr * yr))
            numberUp = x * y;
        else
            numberUp = xr * yr;
        return numberUp;
    }

    this.SheetsNeeded = function(Quantity, NumberUp) {
        return Math.ceil(Quantity / NumberUp);
    }

    this.DigitalPriceFromArea = function(Quantity, Size1, Size2) {
        var setUpFee = 50.0;
        var perSheetRate;
        var numberUp = this.NumberPerSheet(19.5, 13.5, 0.125, Size1, Size2);
        if (numberUp == 0)
            return 0;
        sheetsNeeded = this.SheetsNeeded(Quantity, numberUp);

        if (sheetsNeeded < 100)
            perSheetRate = 1.40;
        else if (sheetsNeeded < 200)
            perSheetRate = 1.30;
        else if (sheetsNeeded < 300)
            perSheetRate = 1.20;
        else if (sheetsNeeded < 400)
            perSheetRate = 1.10;
        else if (sheetsNeeded < 500)
            perSheetRate = 1.00;
        else if (sheetsNeeded < 1000)
            perSheetRate = 0.90;
        else if (sheetsNeeded < 5000)
            perSheetRate = 0.85;
        else
            perSheetRate = 0.80;
        return (setUpFee + (perSheetRate * sheetsNeeded));
    }

//    this.DigitalPriceFromArea = function(Quantity, Size1, Size2) {
//        setUpFee = 50.0;
//        perSheetRate = 1.75;
//        var numberUp = this.NumberPerSheet(19.5, 13.5, 0.125, Size1, Size2);
//        if (numberUp == 0)
//            return 0;
//        sheetsNeeded = this.SheetsNeeded(Quantity, numberUp);
//        return (setUpFee + (perSheetRate * sheetsNeeded));
//    }

    this.OptionsFees = function(SizeIn, Quantity, Price) {
        if (arguments.length != 3)
            alert('OptionsFees() missing required parameters Size, Quantity, Price');
        var temp = 0;
        if ((this.LogoRemoval != null) && (this.LogoRemoval == 'yes'))
            temp += 75;

        if (this.DesignServices != null) {
            switch (this.DesignServices) {
                case 'none': break;
                case 'typesetting': temp += 25; break;
                case 'full': temp += 75; break;
            }
        }

        if (this.Proof != null) {
            switch (this.Proof) {
                case 'pdf': break;
                case 'matchprint': temp += 30; break;
            }
        }

        if (this.Finishing != null) {
            if (this.PrintingMethod == PrintingMethods.Traditional) {
                switch (this.Finishing) {
                    case 'None': break;
                    case 'Score Only': temp += 100; break;
                    case 'Perf Only': temp += 100; break;
                    case 'Score/Fold': temp += 150; break;
                    case 'Perf/Fold': temp += 150; break;
                }
            }
            else
                switch (this.Finishing) {
                case 'None': break;
                case 'Score Only': temp += 75; break;
                case 'Perf Only': temp += 100; break;
                case 'Score/Fold': temp += 100; break;
                case 'Perf/Fold': temp += 100; break;
            }
        }

        if ((this.TextRemoval != null) && (this.TextRemoval == 'yes'))
            temp += 50;

        var sz = this.SizeNameToSize(SizeIn);
        var nps = this.NumberPerSheet(19.5, 13.5, 0.125, sz.width, sz.height);
        var shts = this.SheetsNeeded(Quantity, nps);

        if (this.HiGloss != null)
            temp += this.HiGlossFees(this.HiGloss, shts);

        if ((this.VariableData != null) && (this.VariableData == true)) {
            temp += this.VariableDataFees(Price);
        }
        temp += this.RoundCornerAndPunchFees(Quantity);
        return Math.ceil(temp);
    }

    this.VariableDataFees = function(PrintFees) {
        return Math.ceil(PrintFees * 0.2);
    }

    this.HiGlossFees = function(SidesIn, Sheets) {
        var temp = 40; // setup fee
        switch (SidesIn) {
            case Sides.None: temp = 0; break;
            case Sides.Front:
            case Sides.Back: temp += (0.25 * Sheets); break;
            case Sides.Both: temp += (0.5 * Sheets); break;
            default: alert('no match for sides (' + SidesIn + ')');
        }
        return Math.ceil(temp);
    }

    this.RoundCornerAndPunchFees = function(Quantity) {

        // Round corner and punch is $75 setup for one or $100 setup for both, plus $5/M for either ($10/M for both).

        var setupFee = 0;
        var runMult = 0;
        if ((this.RoundCorner != null) && (this.RoundCorner == true)) {
            setupFee += 75;
            runMult += 1;
        }
        if ((this.HolePunch != null) && (this.HolePunch == true)) {
            setupFee += 75;
            runMult += 1;
        }
        setupFee = Math.min(setupFee, 100);

        var runFee = (runMult * 5) * (Quantity / 1000);
        var temp = Math.ceil(setupFee + runFee);
        return temp;
    }

    this.TurnaroundFee = function(Price, Days) {
        var tf;
        switch (parseInt(Days)) {
            case 1: tf = 1 * Price; break;
            case 2: tf = 0.75 * Price; break;
            case 3: tf = 0.5 * Price; break;
            case 4: tf = 0.25 * Price; break;
            default: tf = 0; break;
        }
        return tf;
    }

    this.ProofFee = function(Proof) {
        var pf;
        switch (Proof) {
            case 'Matchprint': pf = 30; break;
            default: pf = 0; break;
        }
        return pf;
    }

    this.StockFee = function(Stock, Sheets) {
        return (Sheets * 1);
    }
}