import { JV } from './jpc_value_define';
import { JpcBand } from './jpc_band';
import { JpcFlowTabClass as JpcFlowTab } from './jpc_flow_tab';
import { JpcBillTabSrvClass as JpcBillTab } from './jpc_bill_tab';
import { JpcCrossTabClass as JpcCrossTab } from './jpc_cross_tab';
import { JpcField } from './jpc_field';
import { JpcParam } from './jpc_param';
import { JpcFunc } from './jpc_function';
import { JpcEvent } from './jpc_event';
import { JpcData } from './jpc_data';
import { JpcCommonHelper } from './helper/jpc_helper_common';
import {
  IDefProperties,
  IFormula,
  IParams,
  ICurrent_RPT,
  ICustomizeCfg,
  ITargetFields,
  IRptTpl,
  IDataObj,
  IBands,
  IControlCollection,
  IStyles,
  BorderStyle,
  IFontSubCollection,
  IControlSubCollection,
  IRstPage,
  IMergeBand,
  IFormulasObject,
} from '../interface/basic';
import {
  IFlowTabClass,
  IBillTabClass,
  ICostTabClass,
} from '../interface/classType';
import { IPagingOption } from '../interface/enum';
import { Key } from 'readline';
import { formulaExec } from './formulasFun';

export class JpcExClass {
  flowTab!: IFlowTabClass;
  flowTabEx!: IFlowTabClass;
  billTab!: IBillTabClass;
  crossTab!: ICostTabClass;
  isFollowMode: boolean = false;
  totalPages: number = 0;
  exTotalPages: number = 0;
  runTimePageData: { currentPage?: number };
  fields: ITargetFields;
  params: IParams;
  formulas: IFormula[];
  events: any;
  formulasObject: IFormulasObject = {};

  constructor(rptTpl: IRptTpl) {
    if (rptTpl.流水式表_信息) {
      this.flowTab = new JpcFlowTab(false);
      this.isFollowMode = false;
    }
    if (rptTpl.流水式表_拓展信息) {
      this.flowTabEx = new JpcFlowTab(true);
      if (rptTpl.流水式表_拓展信息.流水拓展显示模式 === '紧随模式') {
        this.isFollowMode = true;
      }
    }
    if (rptTpl.账单式表_信息) {
      this.billTab = new JpcBillTab();
    }
    //let dt1 = new Date();
    if (rptTpl.交叉表_信息) {
      this.crossTab = new JpcCrossTab();
    }
    this.runTimePageData = {};
    this.fields = JpcField.createNew(rptTpl);
    this.params = JpcParam.createNew(rptTpl);
    this.formulas = JpcFunc.createNew(rptTpl);
    this.events = JpcEvent.createNew(rptTpl);
  }

  analyzeData(
    rptTpl: IRptTpl,
    dataObj: IDataObj,
    defProperties: IDefProperties,
    option: string,
    outputType: string
  ) {
    let me = this,
      dftPagingOption = option || IPagingOption.normal;
    //1. data object
    let dataHelper: any = JpcData.createNew();

    // 主要是通过计算rptTpl参数里面的 指标_数据_映射 属性中的公式，赋值于dataObj中的相对应（根据）的属性
    me.executeFormulas('before_analyzing', rptTpl, dataObj, me); //在分析前运行，主要是增加灵活性，比如：重新编排数据的主从关系
    if (me.crossTab) {
      me.executeFormulas('before_paging', rptTpl, dataObj, me);
      dataHelper.analyzeData(rptTpl, dataObj);
      me.crossTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
    } else {
      dataHelper.analyzeData(rptTpl, dataObj);
      //2. tab object
      //pre-condition: the data should be sorted in SQL/NoSQL level!
      //let dt1 = new Date();
      if (me.flowTab) {
        me.flowTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
        if (me.flowTabEx) {
          me.flowTabEx.sorting(
            rptTpl,
            dataObj,
            dataHelper.exDataSeq.slice(0),
            me
          );
        }
      }

      if (me.billTab) {
        // 先记录下账单式表_信息.账单式表_数据中的数据相对应于从 数据指标_集合 中的相对应的数组序号，后面便于计算
        // me.billTab.sorting(rptTpl, dataObj, dataHelper.dataSeq.slice(0), me);
        //edit by lish,方法中需要的参数只有一个，但是这里存入了4个
        me.billTab.sorting(rptTpl);
      }
      //3. formulas
      // 主要是通过计算rptTpl参数里面的 指标_数据_映射 属性中的公式，赋值于dataObj中的相对应（根据）的属性
      me.executeFormulas('before_paging', rptTpl, dataObj, me);
    }
    //4. paging
    //获取总页数
    me.paging(rptTpl, dataObj, defProperties, dftPagingOption);
    //alert('analyzeData was completed!');
    //for garbage collection:
    dataHelper = null;
  }
  //获取总页数
  paging(
    rptTpl: IRptTpl,
    dataObj: IDataObj,
    defProperties: IDefProperties,
    option: string
  ) {
    let me = this,
      dftPagingOption = option || IPagingOption.normal;
    if (me.flowTab) {
      if (me.isFollowMode) {
        me.totalPages = me.flowTab.preSetupPages(
          rptTpl,
          dataObj,
          defProperties,
          dftPagingOption,
          me,
          me.flowTabEx
        );
      } else {
        me.totalPages = me.flowTab.preSetupPages(
          rptTpl,
          dataObj,
          defProperties,
          dftPagingOption,
          me,
          null
        );
        if (me.flowTabEx) {
          me.exTotalPages = me.flowTabEx.preSetupPages(
            rptTpl,
            dataObj,
            defProperties,
            dftPagingOption,
            me,
            null
          );
          //console.log('ad-hoc flow pages: ' + me.exTotalPages);
        }
        me.totalPages += me.exTotalPages;
      }
    } else if (me.crossTab) {
      //me.totalPages = me.crossTab.preSetupPages(rptTpl, defProperties, dftPagingOption);
      me.totalPages = me.crossTab.preSetupPages(
        rptTpl,
        defProperties,
        IPagingOption.normal
      ); //infinity对交叉表来说无意义
    } else if (me.billTab) {
      me.totalPages = me.billTab.paging(rptTpl, dataObj);
    }
  }

  //根据步骤，对formulas中的计算式进行处理，并赋值到相应属性中
  executeFormulas(
    runType: string,
    $CURRENT_TEMPLATE: IRptTpl,
    $CURRENT_DATA: IDataObj,
    $CURRENT_RPT: ICurrent_RPT
  ) {
    return formulaExec(runType, $CURRENT_TEMPLATE, $CURRENT_DATA, $CURRENT_RPT);
  }

  outputAsPreviewPage(rptTpl: IRptTpl, defProperties: IDefProperties) {
    let me = this,
      rst: any = {};
    rst.control_collection = private_buildDftControls(
      rptTpl,
      defProperties === null ? null : defProperties.ctrls
    );
    rst.style_collection = private_buildDftStyles(
      rptTpl,
      defProperties === null ? null : defProperties.styles
    );
    rst.font_collection = private_buildDftFonts(
      rptTpl,
      defProperties === null ? null : defProperties.fonts
    );
    rst.打印页面_信息 = {};
    rst.打印页面_信息.报表名称 = rptTpl.主信息.报表名称;
    rst.打印页面_信息.纸张宽高 = JpcCommonHelper.getPageSize(rptTpl);
    rst.打印页面_信息.页边距 = rptTpl.主信息.页边距;
    rst.items = [];
    let bands = JpcBand.createNew(rptTpl, defProperties);
    try {
      function getPageMergeBorder() {
        let mergeRst = {} as IMergeBand;
        if (bands.MergeBand) {
          let mergedBand = bands.MergeBand;
          mergeRst.Left = parseInt(mergedBand.Left.toFixed(0));
          mergeRst.Right = parseInt(mergedBand.Right.toFixed(0));
          mergeRst.Top = parseInt(mergedBand.Top.toFixed(0));
          mergeRst.Bottom = parseInt(mergedBand.Bottom.toFixed(0));
        }
        return null;
      }
      //1.
      let rstPage: IRstPage = {
        cells: [],
      };
      rstPage.page_seq = 1;
      if (me.flowTab) {
        rstPage.cells = me.flowTab.outputAsPreviewPage(
          rptTpl,
          bands,
          rst.control_collection,
          me
        );
      } else if (me.crossTab) {
        rstPage.cells = me.crossTab.outputAsPreviewPage(
          rptTpl,
          bands,
          rst.control_collection,
          me,
          null as unknown as ICustomizeCfg
        ); //方法中定义了5个参数，这里只传进去了4个参数，故加一个参数，by lish
      } else if (me.billTab) {
        rstPage.cells = me.billTab.outputAsPreviewPage(
          rptTpl,
          bands,
          rst.control_collection,
          me
        );
      }
      let pageMergeBorder = getPageMergeBorder();
      if (pageMergeBorder) {
        rstPage.page_merge_border = pageMergeBorder;
      }
      rst.items.push(rstPage);
      //2.
      if (bands.MergeBand) {
        let band = bands.MergeBand;
        let mergedBand: IMergeBand = {
          Left: parseInt(band.Left.toFixed(0)),
          Right: parseInt(band.Right.toFixed(0)),
          Top: parseInt(band.Top.toFixed(0)),
          Bottom: parseInt(band.Bottom.toFixed(0)),
          style: band.style,
        };
        rst.MergeBand = mergedBand;
      }
    } catch (exception) {
      console.log(exception);
    } finally {
      bands = null;
    }
    return rst;
  }

  outputAsSimpleJSONPageArray(
    rptTpl: IRptTpl,
    dataObj: IDataObj,
    startPage: number,
    endPage: number,
    defProperties: IDefProperties,
    customizeCfg: ICustomizeCfg
  ) {
    let me = this,
      rst: any = {};
    if (startPage > 0 && startPage <= endPage && endPage <= me.totalPages) {
      rst.control_collection = private_buildDftControls(
        rptTpl,
        defProperties === null ? null : defProperties.ctrls
      );
      rst.style_collection = private_buildDftStyles(
        rptTpl,
        defProperties === null ? null : defProperties.styles
      );
      rst.font_collection = private_buildDftFonts(
        rptTpl,
        defProperties === null ? null : defProperties.fonts
      );
      rst.打印页面_信息 = {};
      rst.打印页面_信息.报表名称 = rptTpl.主信息.报表名称;
      rst.打印页面_信息.纸张宽高 = JpcCommonHelper.getPageSize(rptTpl);
      rst.打印页面_信息.页边距 = rptTpl.主信息.页边距;
      rst.items = [];
      //初始化band（每个大板块的属性）
      let bands = JpcBand.createNew(rptTpl, defProperties);
      try {
        for (let page = startPage; page <= endPage; page++) {
          me.runTimePageData.currentPage = page;
          this.formulasObject = me.executeFormulas(
            'before_output',
            rptTpl,
            dataObj,
            me
          );
          // console.log('=======================');
          rst.items.push(
            me.outputAsSimpleJSONPage(
              rptTpl,
              dataObj,
              bands,
              page,
              rst.control_collection,
              customizeCfg
            )
          );
        }
        if (bands.MergeBand) {
          let band = bands.MergeBand;
          let mergedBand: IMergeBand = {
            Left: parseInt(band.Left.toFixed(0)),
            Right: parseInt(band.Right.toFixed(0)),
            Top: parseInt(band.Top.toFixed(0)),
            Bottom: parseInt(band.Bottom.toFixed(0)),
            style: band.style,
          };

          rst.MergeBand = mergedBand;
        }
      } catch (exception) {
        console.log(exception);
      } finally {
        bands = null;
      }
    }
    return rst;
  }

  outputAsSimpleJSONPage(
    rptTpl: IRptTpl,
    dataObj: IDataObj,
    bands: IBands,
    page: number,
    controls: IControlCollection,
    customizeCfg: ICustomizeCfg
  ) {
    let me = this,
      rst: any = null;
    function getPageMergeBorder() {
      // let mergeRst = null;
      let mergeRst = {} as IMergeBand;
      if (bands.MergeBand) {
        let mergedBand = bands.MergeBand;
        mergeRst.Left = parseInt(mergedBand.Left.toFixed(0));
        mergeRst.Right = parseInt(mergedBand.Right.toFixed(0));
        mergeRst.Top = parseInt(mergedBand.Top.toFixed(0));
        mergeRst.Bottom = parseInt(mergedBand.Bottom.toFixed(0));
      }
      return mergeRst;
      // return false;
    }
    if (me.totalPages >= page) {
      rst = {};
      rst.page_seq = page;
      //rst.cells = [];
      let adHocMergePos: any = null;
      if (me.flowTab) {
        if (me.totalPages - me.exTotalPages >= page) {
          if (me.flowTab.paging_option === JV.PAGING_OPTION_INFINITY) {
            adHocMergePos = {};
          }
          rst.cells = me.flowTab.outputAsSimpleJSONPage(
            rptTpl,
            dataObj,
            page,
            bands,
            controls,
            adHocMergePos,
            me,
            customizeCfg
          );
          if (adHocMergePos) {
            adHocMergePos.纸张宽高 = JpcCommonHelper.getPageSize(rptTpl);
            rst.page_merge_pos = adHocMergePos;
          }
        } else {
          if (!me.isFollowMode) {
            rst.cells = me.flowTabEx.outputAsSimpleJSONPage(
              rptTpl,
              dataObj,
              page - (me.totalPages - me.exTotalPages),
              bands,
              controls,
              adHocMergePos,
              me,
              customizeCfg
            );
          }
        }
      } else if (me.crossTab) {
        rst.cells = me.crossTab.outputAsSimpleJSONPage(
          rptTpl,
          dataObj,
          page,
          bands,
          controls,
          me,
          customizeCfg
        );
      } else if (me.billTab) {
        rst.cells = me.billTab.outputAsSimpleJSONPage(
          rptTpl,
          dataObj,
          page,
          bands,
          controls,
          me,
          customizeCfg
        );
      }
      if (
        !(me.flowTab && me.flowTab.paging_option === IPagingOption.infinity)
      ) {
        let pageMergeBorder = getPageMergeBorder();
        if (pageMergeBorder) {
          rst.page_merge_border = pageMergeBorder;
        }
      }
    }
    return rst;
  }
}

//暂定
const private_buildDftItems = (
  rptTpl: IRptTpl,
  dftCollection: IControlSubCollection[] | IFontSubCollection[] | null,
  nodeName: string
) => {
  const rst: any = {};
  if (dftCollection) {
    for (let i = 0; i < dftCollection.length; i++) {
      const { ID, ...dftCollectionProps } = dftCollection[i];
      rst[dftCollection[i].ID] = { ...dftCollectionProps };
    }
    const propArray =
      nodeName === 'control_collection' ? JV.CONTROL_PROPS : JV.FONT_PROPS;
    if (
      rptTpl &&
      rptTpl[nodeName as keyof IRptTpl] &&
      rptTpl[nodeName as keyof IRptTpl].length
    ) {
      for (let i = 0; i < rptTpl[nodeName as keyof IRptTpl].length; i++) {
        const rptDftItem = rptTpl[nodeName as keyof IRptTpl][i];
        if (rst[rptDftItem.ID] === undefined) {
          const item: any = {};
          for (let j = 0; j < propArray.length; j++) {
            item[propArray[j]] = rptDftItem[propArray[j]];
          }
          rst[rptDftItem.ID] = item;
        }
      }
    }
  }
  return rst;
};

function private_buildDftControls(
  rptTpl: IRptTpl,
  dftControlCollection: IControlSubCollection[] | null
) {
  return private_buildDftItems(
    rptTpl,
    dftControlCollection,
    'control_collection'
  );
}

function private_buildDftFonts(
  rptTpl: IRptTpl,
  dftFontCollection: IFontSubCollection[] | null
) {
  return private_buildDftItems(rptTpl, dftFontCollection, 'font_collection');
}

function private_buildDftStyles(
  rptTpl: IRptTpl,
  dftStyleCollection: IStyles[] | null
) {
  const rst: any = {};
  function private_CopyBorder(destItem: BorderStyle, srcItem: BorderStyle) {
    destItem.LineWeight = srcItem.LineWeight;
    destItem.DashStyle = srcItem.DashStyle;
    destItem.Color = srcItem.Color;
  }
  if (dftStyleCollection) {
    for (let i = 0; i < dftStyleCollection.length; i++) {
      const item: any = {};
      if (
        dftStyleCollection[i].border_style &&
        dftStyleCollection[i].border_style.length > 0
      ) {
        for (let j = 0; j < dftStyleCollection[i].border_style.length; j++) {
          const borderItem = {} as BorderStyle;
          private_CopyBorder(borderItem, dftStyleCollection[i].border_style[j]);
          item[dftStyleCollection[i].border_style[j].Position] = borderItem;
        }
      }
      rst[dftStyleCollection[i].ID] = item;
    }
    if (
      rptTpl &&
      rptTpl.style_collection &&
      rptTpl.style_collection.length > 0
    ) {
      for (let i = 0; i < rptTpl.style_collection.length; i++) {
        const rptDftItem: any = rptTpl.style_collection[i];
        if (rst[rptDftItem.ID] === undefined) {
          if (rptDftItem.ID.indexOf('_AutoHeightMerge_Top') > 0) {
            const key = rptDftItem.ID.substr(
              0,
              rptDftItem.ID.indexOf('_AutoHeightMerge_Top')
            );
            if (rst[key]) {
              const item: any = {};
              if (rst[key].Left) {
                item.Left = {};
                private_CopyBorder(item.Left, rst[key].Left);
              }
              if (rst[key].Right) {
                item.Right = {};
                private_CopyBorder(item.Right, rst[key].Right);
              }
              if (rst[key].Top) {
                item.Top = {};
                private_CopyBorder(item.Top, rst[key].Top);
              }
              rst[rptDftItem.ID] = item;
            }
          } else if (rptDftItem.ID.indexOf('_AutoHeightMerge_Middle') > 0) {
            const key = rptDftItem.ID.substr(
              0,
              rptDftItem.ID.indexOf('_AutoHeightMerge_Middle')
            );
            if (rst[key]) {
              const item: any = {};
              if (rst[key].Left) {
                item.Left = {};
                private_CopyBorder(item.Left, rst[key].Left);
              }
              if (rst[key].Right) {
                item.Right = {};
                private_CopyBorder(item.Right, rst[key].Right);
              }
              rst[rptDftItem.ID] = item;
            }
          } else if (rptDftItem.ID.indexOf('_AutoHeightMerge_Bottom') > 0) {
            const key = rptDftItem.ID.substr(
              0,
              rptDftItem.ID.indexOf('_AutoHeightMerge_Bottom')
            );
            if (rst[key]) {
              const item: any = {};
              if (rst[key].Left) {
                item.Left = {};
                private_CopyBorder(item.Left, rst[key].Left);
              }
              if (rst[key].Right) {
                item.Right = {};
                private_CopyBorder(item.Right, rst[key].Right);
              }
              if (rst[key].Bottom) {
                item.Bottom = {};
                private_CopyBorder(item.Bottom, rst[key].Bottom);
              }
              rst[rptDftItem.ID] = item;
            }
          } else {
            const item: any = {};
            for (let j = 0; j < rptDftItem.border_style.length; j++) {
              const borderItem = {} as BorderStyle;
              private_CopyBorder(borderItem, rptDftItem.border_style[j]);
              item[rptDftItem.border_style[j].Position] = borderItem;
            }
            rst[rptDftItem.ID] = item;
          }
        }
      }
    }
  }
  return rst;
}
