var pdfkit  = require('pdfkit');
var fs      = require('fs');
var path    = require('path');
var sizes   = require('./standardPageSizes');
var thai    = require('./thai');
var barcode = require('./barcode');

var fontNormal  = path.normalize(__dirname + '/../fonts/THSarabun.ttf');
var fontBold    = path.normalize(__dirname + '/../fonts/THSarabunBold.ttf');

var NSReport = function() { };

NSReport.prototype.createDocument = function(reportDefinition, data) {
  var pageSize = pageSize2widthAndHeight(reportDefinition.pageSize || 'a4');
  reportDefinition.pageOrientation = reportDefinition.pageOrientation || 'portrait';
  if (reportDefinition.pageOrientation.toLowerCase() === 'landscape') {
    pageSize = { width: pageSize.height, height: pageSize.width};
    pageSize.orientation = 'landscape';
  } else {
    pageSize.orientation = 'portrait';
  }
  this.imagePath = reportDefinition.imagePath || __dirname + '/../public';

  this.pdfKitDoc = new pdfkit({
      size: [pageSize.width, pageSize.height],
      compress: false,
      bufferPages: true,
      margin: 72
    }, {
      Producer: 'NSReport',
      Creator: 'NSReport',
      Title: 'NSReport',
      Author: 'NSReport',
      Subject: 'NSReport',
      Keywords: 'NSReport'
    });

  this.pdfKitDoc.registerFont('THSarabunNew1', fontNormal, 'TH Sarabun New');
  this.pdfKitDoc.registerFont('THSarabunNew1-Bold', fontBold, 'TH Sarabun New Bold');

  this.page = pageSize;
  this.x = reportDefinition.margin[3];
  this.y = reportDefinition.margin[0];
  this.offsetX = this.x;
  this.offsetY = this.y;
  this.fontCount = [0,0];
  this.numFont = [1,1];
  this.data = data;
  this.isDebug = !!reportDefinition.debug;

  for (var i = 0; i < reportDefinition.RH.length; i++) {
    this.renderSection(reportDefinition.RH[i], data[0]);
    if (reportDefinition.RH[i].pageBreakAfter===true) {
      this.pdfKitDoc.addPage(this.pdfKitDoc.option);
      this.offsetX = this.x;
      this.offsetY = this.y;
    }
  };

  var printHeader = true;
  var row = 0;
  var totalRows = data.length;
//  console.log('data=', data);
  var pageHeight = pageSize.height -  reportDefinition.margin[0]/*top*/ -  reportDefinition.margin[2] /*bottom*/;
  //console.log('contentHeight=', contentHeight);

  var flag_group = false;
  var group_row = 0;  
  while (row < totalRows) {
    this.rowNum = row;

    if(flag_group) {
      this.pdfKitDoc.addPage(this.pdfKitDoc.option);
      this.offsetX = this.x;
      this.offsetY = this.y;
    }

    if (printHeader===true) {

      var contentHeight = pageHeight;
      var numRow = 0; // number of record on page

      reportDefinition.GH = reportDefinition.GH || [];
      reportDefinition.GF = reportDefinition.GF || [];

      for (var i = 0; i < reportDefinition.PH.length; i++) {
        var height = this.renderSection(reportDefinition.PH[i], data[row], contentHeight);
        if (height===-1) throw 'renderSection:: reportDefinition.PH';
        contentHeight -= height;
      }

      for (var i = 0; i < reportDefinition.GH.length; i++) {
        var height = this.renderSection(reportDefinition.GH[i], data[row], contentHeight);
        if (height===-1) throw 'renderSection:: reportDefinition.GH';
        contentHeight -= height;
      }
      
      for (var i = 0; i < reportDefinition.PF.length; i++) {
        var height = this.measureSection(reportDefinition.PF[i], data[row], contentHeight);
        if (height===-1) throw 'measureSection:: reportDefinition.PF';
        contentHeight -= height;
      }

      for (var i = 0; i < reportDefinition.GF.length; i++) {
        var height = this.measureSection(reportDefinition.GF[i], data[row], contentHeight);
        if (height===-1) throw 'measureSection:: reportDefinition.GF';
        contentHeight -= height;
      }

      printHeader = false;
    }

    var height = 0;

    for (var i = 0; i < reportDefinition.DT.length; i++) {
      if (data[row].group_row != undefined) {
        if(group_row >= data[row].group_row)
        {
          flag_group = true;
          group_row = 0;
        } else {
          flag_group = false;
          group_row = data[row].group_row;
        }
      }

      if(!flag_group) {
        var height2 = this.renderSection(reportDefinition.DT[i], data[row], contentHeight);
        if (height2 != -1) height+=height2;
      } else {
        height = 0;
      }
    }

    if (height === 0) {
      if (numRow==0) {
        console.log('ERROR3');
        throw 'ERROR3';
      }

      printHeader = true;
      for (var i = 0; i < reportDefinition.PF.length; i++) {
        var height2 = this.renderSection(reportDefinition.PF[i], data[row], 0);
        if (height2===-1) throw 'renderSection:: reportDefinition.PF';
        contentHeight -= height2;
      }

      if(flag_group) {
        for (var i = 0; i < reportDefinition.GF.length; i++) {
          var height = this.renderSection(reportDefinition.GF[i], data[row-1], 0);
          if (height===-1) throw 'renderSection:: reportDefinition.GF';
          contentHeight -= height;
        }
      }

      if(!flag_group) {
        this.pdfKitDoc.addPage(this.pdfKitDoc.option);
        this.offsetX = this.x;
        this.offsetY = this.y;
      }
      continue;
    }

    contentHeight -= height;
    numRow++;
    row++;
  }

  for (var i = 0; i < reportDefinition.PF.length; i++) {
    var height2 = this.renderSection(reportDefinition.PF[i], data[row-1], 0);
    if (height2===-1) throw 'renderSection:: reportDefinition.PF';
    contentHeight -= height2;
  }

  for (var i = 0; i < reportDefinition.GF.length; i++) {
    console.log(row);
    var height = this.renderSection(reportDefinition.GF[i], data[row-1], 0);
    if (height===-1) throw 'renderSection:: reportDefinition.GF';
    contentHeight -= height;
  }

  for (var i = 0; i < reportDefinition.RF.length; i++) {
    var height2 = this.renderSection(reportDefinition.RF[i], data[row-1], 0);
    if (height2===-1) {
      console.error('ERROR4');
      throw 'ERROR4';
    }
    contentHeight -= height2;
  }

  return this.pdfKitDoc;
}

////////////////////////////////////////
// private function
////////////////////////////////////////

NSReport.prototype.measureSection = function (section, row) {
  var maxHeight = 0;
  var printState = this;
  //console.log('jack');
  if (section.overlay===true) {
    return 0;
  }
  section.items.forEach(function(item) {
    if (typeof item.show == 'function') {
      if (!item.show(row, printState)) {
        return;
      }
    }
    if (item.type == 'text' || item.type == 'money' || item.type == 'number') {
      maxHeight = Math.max(maxHeight, item.y+(item.h||10));
    } else if (item.type == 'image') {
      maxHeight = Math.max(maxHeight, item.y+item.fit[1]);
    } else if (item.type == 'line') {
      maxHeight = Math.max(maxHeight, item.y2);
    } else if (item.type == 'rectangle' || item.type=='barcode') {
      maxHeight = Math.max(maxHeight, item.y+item.h);
    } else if (item.type == 'hline') {
      maxHeight = maxHeight;
    } else if (item.type == 'vline') {
      maxHeight = Math.max(maxHeight, item.y+item.h);
    }
  });
  return maxHeight;
}

NSReport.prototype.renderSection = function (section, row, limit) {
  var printState = this;
  var doc = this.pdfKitDoc;
  var x = this.offsetX;
  var y = this.offsetY;
  var maxHeight = this.measureSection(section, row);

  if (limit > 0 && maxHeight > limit) {
//    console.log('**************', maxHeight, limit);
    return -1;
  }


  section.items.forEach(function(item, i) {
    if (this.isDebug) {
      if (item.type=='text' || item.type=='money' || item.type == 'number' || item.type=='image' || item.type=='circle' || item.type=='rectangle') {
        doc.lineWidth(0.5);
        var dim = {
          x:item.x,
          y:item.y,
          w:item.w,
          h:item.h
        };
        if (item.type=='image') {
          dim.w = dim.h = item.fit;
        }
        doc.undash();
        doc.rect(x + dim.x, y + dim.y, dim.w, dim.h);
        doc.stroke();
      }
    }
    if (typeof item.show == 'function') {
      if (!item.show(row, printState)) {
        return;
      }
    }
    if (item.color) {
      doc.fillColor(item.color);
    } else {
      doc.fillColor('#000');
    }
    if (item.type == 'text' || item.type=='money' || item.type == 'number') {
    //  maxHeight = Math.max(maxHeight, item.y+(item.h||10));
      doc.fontSize(item.fontSize);
      var opt = {width:item.w, height:item.h, lineBreak:false, ellipsis: true};
      if (typeof item.lineHeight === 'number') {
        delete opt.lineBreak;
        delete opt.ellipsis;
        opt.lineGap = item.fontSize*item.lineHeight - item.fontSize;
      }
      if (typeof item.align === 'string') {
        opt.align = item.align;
      }

      var text = '';
      if (typeof item.field === 'string') {
        if(typeof row[item.field] === 'number' && item.type == 'money') {
          text = ''+ (row[item.field] == undefined ? '-' : NumbertoMoney(row[item.field]));
        } else if(typeof row[item.field] === 'number' && item.type == 'number') {
          text = ''+ (row[item.field] == undefined ? '-' : Math.round(NumbertoMoney(row[item.field])));
        } else {
          text = ''+row[item.field] || '';
        }
        
      } else if (typeof item.field === 'function') {
        text = item.field(row, this.rowNum, this.data) || '';
      } else {
        var itemText = item.text;
        var field = /\{\{(.*?)\}\}/ig.exec(itemText);
        while(field != null) {
          itemText = itemText.replace(field[0], row[field[1]]); 
          field = /\{\{(.*?)\}\}/ig.exec(itemText);
        } 
        text = ''+itemText || '';
      }

      var text = thai(text);
      
      if (!!item.bold) {
        this.fontCount[1]++;
        if (this.fontCount[1] > 20) {
          this.numFont[1]++;
          this.fontCount[1] = 0;
//          console.log('numFont[1]=', this.numFont[1]);
        }
        this.pdfKitDoc.registerFont('THSarabunNew'+this.numFont[1]+'-Bold', fontBold, 'TH Sarabun New Bold');
        doc.font('THSarabunNew'+this.numFont[1]+'-Bold');
      } else {
        this.fontCount[0]++;
        if (this.fontCount[0] > 10) {
          this.numFont[0]++;
          this.fontCount[0] = 0;
//          console.log('numFont[0]=', this.numFont[0]);
        }
        this.pdfKitDoc.registerFont('THSarabunNew'+this.numFont[0], fontNormal, 'TH Sarabun New');
        doc.font('THSarabunNew'+this.numFont[0]);
      }
      doc.text(text, x+item.x, y+item.y, opt);
    } else if (item.type == 'image') {
    //  maxHeight = Math.max(maxHeight, item.y+item.fit[1]);
      doc.image(path.normalize(this.imagePath + '/' + item.image), x+item.x, y+item.y, {fit: item.fit});
    } else if (item.type == 'line') {
  //    maxHeight = Math.max(maxHeight, item.y2);
      if (item.style=='dotted') {
        doc.dash(1, {space: 2});
      } else if (item.style=='dashed') {
        doc.dash(3, {space: 3});
      } else {
        doc.undash();
      }
      doc.lineWidth(item.lineWidth || 1);
      doc.moveTo(x+item.x1, y+item.y1);
      doc.lineTo(x+item.x2, y+item.y2);
      doc.stroke();
    } else if (item.type == 'hline') {
      if (item.style=='dotted') {
        doc.dash(1, {space: 2});
      } else if (item.style=='dashed') {
        doc.dash(3, {space: 3});
      } else {
        doc.undash();
      }
      doc.lineWidth(item.lineWidth || 1);
      doc.moveTo(x+item.x, y+item.y);
      doc.lineTo(x+item.x+item.w, y+item.y);
      doc.stroke();
    } else if (item.type == 'vline') {
      if (item.style=='dotted') {
        doc.dash(1, {space: 2});
      } else if (item.style=='dashed') {
        doc.dash(3, {space: 3});
      } else {
        doc.undash();
      }
      doc.lineWidth(item.lineWidth || 1);
      doc.moveTo(x+item.x, y+item.y);
      doc.lineTo(x+item.x, y+item.y+item.h);
      doc.stroke();
    } else if (item.type == 'rectangle') {
  //    maxHeight = Math.max(maxHeight, item.y+item.h);
      if (item.style=='dotted') {
        doc.dash(1, {space: 2});
      } else if (item.style=='dashed') {
        doc.dash(3, {space: 3});
      } else {
        doc.undash();
      }
      doc.lineWidth(item.lineWidth || 1);
      if (typeof item.radius === 'number') {
        doc.roundedRect(x + item.x, y + item.y, item.w, item.h, item.radius);
      } else {
        doc.rect(x + item.x, y + item.y, item.w, item.h);
      }
      if (item.fillColor && item.color) {
        doc.fillAndStroke(item.fillColor, item.color);
      } else if (item.fillColor && !item.color) {
        doc.fill(item.fillColor);
      } else {
        doc.stroke();
      }
    } else if (item.type == 'circle') {
      doc.lineWidth(item.lineWidth || 1);
      doc.ellipse(x+item.x+item.w/2, y+item.y+item.h/2, item.w/2, item.h/2);
      doc.stroke();
    } else if (item.type == 'barcode') {
      if (!item.format || item.format=='code128') {
        var text = ''+item.text || '';
        if (typeof item.field === 'string') {
          text = ''+row[item.field] || '';
        } else if (typeof item.field === 'function') {
          text = item.field(row, this.rowNum, this.data) || '';
        }
        doc
          .save()
          .translate(x+item.x, y+item.y).fillColor('black').path(barcode.code128(text, item.w, item.h)).fill()
          .restore();
      } else {
        doc.rect(x + item.x, y + item.y, item.w, item.h);
        doc.lineWidth(item.lineWidth || 1);
        doc.moveTo(x+item.x, y+item.y);
        doc.lineTo(x+item.x+item.w, y+item.y+item.h);
        doc.stroke();
        doc.moveTo(x+item.x+item.w, y+item.y);
        doc.lineTo(x+item.x, y+item.y+item.h);
      }
    } else {
      doc.rect(x + item.x, y + item.y, item.w, item.h);
      doc.lineWidth(item.lineWidth || 1);
      doc.moveTo(x+item.x, y+item.y);
      doc.lineTo(x+item.x+item.w, y+item.y+item.h);
      doc.stroke();
      doc.moveTo(x+item.x+item.w, y+item.y);
      doc.lineTo(x+item.x, y+item.y+item.h);
    }
  }.bind(this));

  if (section.overlay===true) {
    maxHeight = 0;
  } else {
    if (section.autoShrink===true) {
      this.offsetY += maxHeight;
    } else if (typeof section.height === 'number') {
      this.offsetY += Math.max(section.height, maxHeight);
    } else {
      this.offsetY += maxHeight;
    }
  }
  return maxHeight;
}

function pageSize2widthAndHeight(pageSize) {
  if (typeof pageSize == 'string' || pageSize instanceof String) {
    var size = sizes[pageSize.toUpperCase()];

    if (!size) {
      throw ('Page size ' + pageSize + ' not recognized');
    }

    console.log('w:', size[0], 'h:', size[1]);

    return {
      width: size[0],
      height: size[1]
    };
  }

  if (typeof pageSize.width === 'undefined'
    || typeof pageSize.height === 'undefined'
    || (typeof pageSize.width !== 'number' && ! (pageSize.width instanceof Number) )
    || (typeof pageSize.height !== 'number' && ! (pageSize.height instanceof Number) )
  ) {
    throw ('Page size ' + pageSize + ' not recognized');
  }

  return pageSize;
}

function fixPageMargins(margin) {
    if (!margin) return null;

    if (typeof margin === 'number' || margin instanceof Number) {
        margin = { left: margin, right: margin, top: margin, bottom: margin };
    } else if (margin instanceof Array) {
        if (margin.length === 2) {
            margin = { left: margin[0], top: margin[1], right: margin[0], bottom: margin[1] };
        } else if (margin.length === 4) {
            margin = { left: margin[0], top: margin[1], right: margin[2], bottom: margin[3] };
        } else throw 'Invalid pageMargins definition';
    }

    return margin;
}

function NumbertoMoney(n) {
    var c = 2, d = ".", t = ",", s = n < 0 ? "-" : "", i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
    return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
}

module.exports = NSReport;
