import { HttpClient } from 'aurelia-fetch-client';

export class PDFExport {

    constructor(controller, config) {

        this.controller = controller;

        for (let key in config) {
            this[key] = config[key];
        }

        this.httpClient = new HttpClient();
        this.httpClient.configure(conf => {
            conf.useStandardConfiguration();
        });

        this.fontcounter = 0;
        this.fontsloaded = 0;
        this.fontData = {
            'roman': { 'name': 'AsapCondensed', 'url': 'assets/fonts/Asap-Regular.ttf', 'data': undefined },
            'bold': { 'name': 'AsapCondensed Bold', 'url': 'assets/fonts/Asap-Bold.ttf', 'data': undefined },
            'italic': { 'name': 'AsapCondensed Italic', 'url': 'assets/fonts/Asap-Italic.ttf', 'data': undefined }
        };

        this.context_url = 'src/sampling-info.json';

        this.lineSpacing = 1.5;
        // this.baseFontSize = 11;
        this.baseFontSize = 10;

        this.axisWidth = 45;
        this.axisOffset = 10;
        this.tickLength = 10;
        this.labelOffset = 5;
        this.height = 180;
        this.width = 215;

        this.offset = {
            x: 4 * this.baseFontSize,
            y: 4 * this.baseFontSize
        };

        // ***MAGIC NUMBERS*** for conversion from svg web layout to pdf print
        this.magicSpacingRatio = 0.425;
        this.magicMagicRatio = 0.49;

        this.diameter = parseFloat(this.iconArray.radius) * 1.18;
        this.dotspacing = this.diameter * this.iconArray.dotspacingRatio * this.magicSpacingRatio;

        this.fontcounter = Object.keys(this.fontData).length;

        this.httpClient.fetch(this.context_url)
            .then(response => response.json())
            .then(data => {
                this.context = data;

                for (let md in this.fontData) {
                    let cfd = this.fontData[md];
                    this.httpClient.fetch(cfd.url)
                        .then(response => response.arrayBuffer())
                        .then(data => {
                            cfd.data = data;
                            this.fontsloaded += 1;
                            if (this.fontsloaded === this.fontcounter) {
                                this.drawPDF();
                            }

                        });
                }
        });

        this.samplers[0].samples = this.samples[0];
        this.samplers[1].samples = this.samples[1];
    }

    listUpdated(list) {
        this.drawPDF(list);
    }

    samplesPerClass(idx) {
        let samplesIsolated = [];
        let samples = [];
        for (let s of this.samples[idx]) {  // deep copy of samples
            samples.push(s);
        }

        for (let cls of this.classes) {
            let arr = samples.filter(function(c) {
                return c === cls.id;
            }, cls);

            samplesIsolated.push(arr);
        }
        return samplesIsolated;
    }

    drawAxis(doc, x_offset) {
        let blockspacing = this.diameter * this.iconArray.blocks.horizontal.spacingRatio;
        let binWidth = (this.iconArray.blocks.horizontal.size * (this.diameter * 1.03 + this.dotspacing) + blockspacing);
        let axisLabel = {de: 'Gewinne', en: 'Profits'};

        let y_baseline = this.iconArray.y_offset + this.height + this.axisOffset - this.labelOffset / 2;

        doc.fillColor('black');
        doc.font(this.fontData.bold.name)
            .fontSize(this.baseFontSize * this.fontRatios.tiny)
            .text(
                axisLabel[this.lang],
                x_offset + binWidth,
                this.iconArray.y_offset + this.height + this.axisOffset,
                { width: 500, align: 'left' }
            )
            .fill();

        let x_magicoffset = (this.diameter - this.dotspacing) * 1.2;

        for (let cidx in this.samplers[0].classes) {
            cidx = parseInt(cidx);
            let bidx = cidx;

            let lines = this.samplers[0].classes[bidx].name[this.lang].split('\n');
            let y = this.iconArray.y_offset + this.height + this.axisOffset + this.labelOffset * 2;

            if (cidx === 0) {
                y = this.iconArray.y_offset + this.height + this.axisOffset;
                doc.font(this.fontData.bold.name);
            } else {
                doc.font(this.fontData.roman.name);
            }

            for (let lidx = 0; lidx < lines.length; ++lidx) {
                doc.text(
                    lines[lidx],
                    x_offset + cidx * binWidth,
                    y + lidx * this.labelOffset * 2
                );
            }

            if (cidx < this.samplers[0].classes.length - 1) {
                let y2 = y_baseline + this.axisOffset * 1.5;
                let y2long = y_baseline + this.axisOffset * 3;
                if (cidx === 0) {
                    y2 = y2long;
                }

                let x = x_offset + (cidx + 1) * binWidth - x_magicoffset;

                doc.moveTo(x, y_baseline - 3 * binWidth)
                    .lineTo(x, y2long)
                    .dash(1, {space: 2})
                    .strokeColor('#aaa')
                    .stroke();

                doc.moveTo(x, y_baseline)
                    .lineTo(x, y2)
                    .dash(100)
                    .strokeColor('#444')
                    .stroke();
            }
        }
        doc.moveTo(x_offset - this.axisOffset, y_baseline)
            .lineTo(x_offset + this.width, y_baseline)
            .dash(500)
            .strokeColor('#444')
            .stroke();
    }

    createIconArray(doc) {

        // hand-adjusted positioning
        this.iconArray.x_offset = this.baseFontSize * 25;
        this.iconArray.y_offset = this.baseFontSize * 5;

        let blockspacing = {
            h: this.diameter * this.iconArray.blocks.horizontal.spacingRatio * 1.5,
            v: this.diameter * this.iconArray.blocks.vertical.spacingRatio * 1.5
        };

        let blocksize = {
            h: this.iconArray.blocks.horizontal.size,
            v: this.iconArray.blocks.vertical.size
        };

        let nrblocks = {
            h: this.iconArray.blocks.horizontal.amount,
            v: this.iconArray.blocks.vertical.amount
        };

        let iaxfirst = this.iconArray.size === 100 ? 50 : 0;


        for (let j = 0; j < 2; ++j) {

            let samplesPerClass = this.samplesPerClass(j);
            let samplesConcat = [];

            for (let i = 0; i < samplesPerClass.length; ++i) {

                for (let l = 0; l < samplesPerClass[i].length; ++l) {  // fill array with all samples of current class
                    samplesConcat.push(i);
                }

                for (let k = 0; k < this.soffsets[i] * this.iconArray.blocks.vertical.amount * blocksize.h * blocksize.v - samplesPerClass[i].length; ++k) {  // fill up block with complementary class
                    samplesConcat.push(undefined);
                }
            }

            let sclength = samplesConcat.length;
            for (let i = 0; i < this.maxSamples - sclength; ++i) {  // fill up the array with either base class id or undefined (placeholder)
                samplesConcat.push(undefined);
            }

            let samples = samplesConcat;

            let x_offset = j * this.iconArray.x_offset + iaxfirst + this.baseFontSize * 4 + this.diameter * this.magicMagicRatio + this.axisOffset;  // x-offset per icon array

            for (let i = 0; i < samples.length; ++i) {

                doc.ellipse(
                    x_offset +
                    // LINE-wise block-spaced layout
                    (this.dotspacing + this.diameter) * Math.floor(i / (nrblocks.v * blocksize.v)) +
                    blockspacing.h * (Math.floor(i / blocksize.h / blocksize.v / nrblocks.h)),

                    this.iconArray.y_offset +  // y-offset
                    this.height - (this.dotspacing + this.diameter) * (i % (nrblocks.v * blocksize.v)),  // blockspacing y
                    this.diameter * this.magicMagicRatio  // radius !!??
                );

                let col = '';
                if (samples[i] === undefined) {
                    col = '#fff';
                } else {
                    col = this.colours[samples[i]];
                }
                doc.fill(col);
            }
            this.drawAxis(doc, x_offset);
        }
    }

    drawPDF() {

        let doc = new PDFDocument(
            {
                size: 'A4',
                // size: 'A5',
                // layout: 'landscape',
                margin: 0
            }
        );

        for (let fd in this.fontData) {
            let cfd = this.fontData[fd];
            doc.registerFont(cfd.name, cfd.data);
        }

        this.stream = doc.pipe(blobStream());

        // meta data
        doc.info.Title = this.title;
        doc.info.Author = this.author;
        doc.info.Subject = this.description;

        // title
        doc.font(this.fontData.bold.name)
            .fontSize(this.baseFontSize * this.fontRatios.large)
            .text(
                this.title,
                this.offset.x,
                this.baseFontSize * this.fontRatios.huge,
                { width: 500 }
            );

        // description
        doc.font(this.fontData.roman.name)
            .fontSize(this.baseFontSize * this.fontRatios.medium);
        doc.text(this.description);

        doc.fontSize(this.baseFontSize * this.fontRatios.small)
            .fillColor('#333333')
            .font(this.fontData.bold.name);

        this.offset.table = 6;

        doc.moveTo(this.offset.x, this.offset.y);
        // reference classes
        for (let i = 0; i < this.referenceClasses.length; ++i) {
            doc.text(
                this.referenceClasses[i].prefix[this.lang] + ' ' + this.samples[i].length + ' ' + this.referenceClasses[i].infix[this.lang] + '\n' +
                this.samplers[i].getStockRatioRepr() + ' ' + this.labels.ratio.stock[this.lang] +
                ' – ' + this.samplers[i].getDepositRatioRepr() + ' ' + this.labels.ratio.deposit[this.lang],
                this.offset.x + i * this.baseFontSize * 25,
                this.offset.table * this.baseFontSize,
                { width: this.baseFontSize * 25, align: 'left' }
            );
        }

        if (this.iconArray.size === 1000) {
            this.iconArray.y_offset = this.baseFontSize * 24;
        } else {
            this.iconArray.y_offset = this.baseFontSize * 24;
        }

        // draw icon arrays inclusive axes
        this.createIconArray(doc);

        // draw ontext
        doc.font(this.fontData.roman.name)
            .fontSize(this.baseFontSize * this.fontRatios.small);

        // reset the text cursor??! for continuous text positioning. !@&^%
        doc.text(
            '',
            this.offset.x,
            this.height + this.iconArray.y_offset * 2.5
        );

        // context
        for (let i = 0; i < this.context.length; ++i) {  // classes array
            doc.font(this.fontData.roman.name);

            let obj = this.context[i];

            if (obj.constructor === Array) {
                let lst = obj.map(function(e) {
                    return e.text;
                });

                doc.list(
                    lst,
                    { width: this.baseFontSize * 45, align: 'left' }
                );
            } else {
                if (obj.type === 'heading') {
                    doc.font(this.fontData.bold.name);
                }

                doc.text(
                    obj.text,
                    { width: this.baseFontSize * 45, align: 'left' }
                );
            }

            doc.moveDown();
        }

        doc.end();

        this.stream.on('finish', () => {
            let url = this.stream.toBlobURL('application/pdf');
            this.controller.updatePDFLink(url);
        });
    }
}
