/*
* dpicker 클래스에 datepicker 적용. input type=date 적용으로 대체함
* */
/*
jQuery("input[type=date]").each((idx,tgt) => {
  jQuery(tgt).attr("type","text");
  jQuery(tgt).wrap("<label class='dpicker'></label>");
  jQuery(tgt).after("<i class='icon bi bi-calendar3'></i>");
});

jQuery(document).on("focus",".dpicker input",function(){
  let format = "yyyy-mm-dd";
  let cformat = ['Y','m','d'];
  let cdmt = "-";
  if( jQuery(this).attr("format") ){
    format = jQuery(this).attr("format");
    cformat = [];
    cdmt = s[s.search(/[^0-9]/)];
    let frow = format.split(cdmt);
    frow.forEach(v=>{
      switch( v ){
        case "yyyy": cformat.push('YY'); break;
        case "yy": cformat.push('Y'); break;
        case "mm": cformat.push('m'); break;
        case "dd": cformat.push('d'); break;
      }
    });
  }

  jQuery(this).datepicker({
    format: format,
    language: "ko",
    autoclose: true,
    orientation: "bottom auto",
  });
  new Cleave(this, {
    date: true,
    delimiter: cdmt,
    datePattern: cformat
  });
});
*/
/*
* 공백제거함수
* */
const trim = function(str){
  if( str || str === 0 ){
    return str.toString().replace(/^\s+|\s+$/g,"");
  }
  return "";
};

/*
* 경고창, 모달, notify 정의
* */
let NotyObj = new AWN();
const kuls_alert = function(msg, sfunc, options){
  return NotyObj.confirm(msg||'실행 메세지가 없습니다.<br/>오류를 확인하세요.',sfunc||false,false,{labels:{confirm: ''}, ...options});
};

const kuls_confirm = function(title, msg, sfunc, ffunc, options){
  //let confirm = NotyObj.confirm(msg||' ',sfunc||(()=>{}),ffunc||(()=>{}),{labels:{confirm: title||msg, confirmOk: '확 인', confirmCancel: '취 소'}, ...options});
  let confirm = NotyObj.confirm(msg||' ',sfunc||(()=>{}),ffunc||(()=>{}),{labels:{confirm: title||msg}, ...options});
  confirm.remove = confirm.delete; //자동 Close 중지용 백업
  if( !sfunc ) confirm.okBtn.addEventListener("click", function(){confirm.remove()}); //Ok 실행함수가 없을경우에만 Ok버튼에 닫기 처리
  confirm.cancelBtn.addEventListener("click", function(){confirm.remove()}); //Cancel 버튼에 닫기 처리
  if( options && options.dontclose ) confirm.delete = ()=>{}; // 기본 닫기함수 무효화
  tab_key_able();
  return confirm;
};

const kuls_modal = function(msg, options){
  let modal = NotyObj.modal(msg, 'kuls_modal', {...options});
  let btn = document.createElement("a");
  btn.classList.add('bi');
  btn.classList.add('bi-x-circle-fill');
  btn.style = "position:absolute; right:6px; top:6px; line-height: 0; cursor:pointer;";
  modal.remove = modal.delete; //자동 Close 중지용 백업
  btn.addEventListener("click",function(){modal.remove();} );
  modal.el.querySelector(".awn-popup-body").append(btn);
  jQuery(modal.el.querySelector(".awn-popup-body:not(:has(.sortable))")).draggable({
  cancel: "label, input, textarea, button, select, a" // 드래그 불가능한 요소 목록
  });
  if( options && options.resizable ) jQuery(modal.el.querySelector(".awn-popup-body")).resizable({
    handles: "n, e, s, w, se, nw",
    grid: [5,5],
  });
  if( options && options.buttons ){
    options.buttons.forEach(btns => {
      document.querySelectorAll(".awn-popup-kuls_modal "+ btns['tgt']).forEach(btn => {
        btn.addEventListener("click", function(e){ btns.func(modal, e); });
      });
    });
  }
  if( options && options.init ){
    options.init(modal);
  }
  if( options && options.dontclose ) modal.delete = ()=>{}; // 기본 닫기함수 무효화
  tab_key_able();
  return modal;
};

const kuls_loading = function(options){
  msg ='<style>#awn-popup-wrapper .awn-popup-body {background-color: #fff0; background-color: #fff0; color: #fff; text-align: center; font-size: 20px;}</style>';
  msg+='<div class="spinner-border m-5" role="status">' +
    '  <span class="visually-hidden">Loading...</span>' +
    '</div>';
  let loading = NotyObj.modal(msg, 'kuls_modal', {...options,isDeleted:false});
  loading.remove = loading.delete; //자동 Close 중지용 백업
  loading.delete = ()=>{};
  return loading;
};

const kuls_success = function(msg){
  NotyObj.success(msg,{durations: {success:800}});
};

const kuls_warning = function(msg){
  NotyObj.warning(msg,{durations: {warning:5000}});
};

const tab_key_able = function(){ //모달창 탭키 인식가능하도록 적용
  let focusable = document.querySelectorAll("#awn-popup-wrapper input:not([type=hidden]), #awn-popup-wrapper textarea, #awn-popup-wrapper button");
  let shiftkey = false;
  focusable.forEach((ipt, idx) => {
    ipt.addEventListener("keydown",function(e){
      switch( e.key ){
        case "Tab":
          if( shiftkey ){
            focusable[(focusable.length + (idx-1)) % focusable.length ].focus();
          }else{
            focusable[(idx+1) % focusable.length ].focus();
          }
          break;
        case "Shift":
          shiftkey = true;
          break;
      }
    });

    ipt.addEventListener("keyup",function(e){
      switch( e.key ){
        case "Shift":
          shiftkey = false;
          break;
      }
    });
  } );
}

/*
* 쿼리2json
* */
const qry2json = function(qry){
  let qryjson  = qry.split(/&amp;|&/).reduce( (js, fld) => {
    fld = fld.split("=");
    js[fld[0]] = fld[1];
    return js;
  }, {});

  return qryjson;
};

/*
* url decode
* */
const urlSplit = function(surl){
  let sppos = surl.indexOf("?"),
  url = "", qry = "", qryjson={};
  if( sppos === -1 ){
    if( /[&=]/.test(surl) ){
      qry = surl;
    }else{
      url = surl;
    }
  }else{
    url = surl.substr(0,sppos);
    qry = surl.substr(sppos+1);
  }
  qryjson = qry2json(qry);

  return { url, qry, qryjson };
};

/*
* 리스트 정렬 함수
* */
const getSortQry = function(qry, ofld, oasc){
  let q2j = qry2json(qry);
  if( ofld ) q2j['ofld'] = ofld;
  if( oasc ) q2j['oasc'] = oasc;

  if( !oasc ){
    if( q2j.oasc == "desc" ){
      q2j.oasc = "asc";
    }else{
      q2j.oasc = "desc";
    }
  }

  return q2j;
};

const sort_page_move = function(qry, ofld, oasc){
  let nqry = getSortQry(qry, ofld, oasc);
  location.href ="?" + Object.keys(nqry).map( key => key+"="+nqry[key] ).join("&");
};

const sort_page_load = function(qry, ofld, oasc){
  let nqry = getSortQry(qry, ofld, oasc);

  document.getElementsByName("ofld")[0].value = nqry.ofld;
  document.getElementsByName("oasc")[0].value = nqry.oasc;
  common_page_move( Object.keys(nqry).map( key => key+"="+nqry[key] ).join("&") );
};

/**
 *  List Load 함수
 */
const list_page_load = (surl, func) => {
  let url = urlSplit(surl);

  if( func ) return func(url.url, url.qry, url.qryjson);
  return false;
};

/**
 * 날짜 변환 함수 (초 -> 분 -> 시간 -> 일)
 */
const dateRformat = ( number, conf ) => {
  number = Number(number);
  let dan = conf?.dan||'s';
  let days = 0, hours = 0, minutes = 0, seconds = 0, rem = 0, retstr = '';

  switch( dan ){
    case "m": //분단위
      number *= 60;
    break;
    case "h": //시간단위
      number *= 60*60;
    break;
  }


  days    = Math.floor( number / (3600*24) );
  rem     = number % (3600*24);
  hours   = Math.floor(rem / 3600);
  rem     = rem % (3600);
  minutes = Math.floor(rem / 60);
  seconds = rem % (60);

  if( days )    retstr += (retstr?' ':'') + days    + (conf?.text?.d||'일');
  if( hours )   retstr += (retstr?' ':'') + hours   + (conf?.text?.h||'시간');
  if( minutes ) retstr += (retstr?' ':'') + minutes + (conf?.text?.m||'분');
  if( seconds ) retstr += (retstr?' ':'') + seconds + (conf?.text?.s||'초');

  return retstr;
}

/**
 * form2url
 */
const form2qry = (form) => {
  let frm = new FormData(form);
  return Array.from(frm.entries()).map( tgt => tgt[0]+'='+tgt[1] ).join("&");
};

/**
 * form2json
 */
const form2Json = (form) => {
  let j_son = {};
  Array.prototype.slice.call(form.elements).forEach(function (field) {
    if (!field.name || field.disabled || ['file', 'reset', 'submit', 'button'].indexOf(field.type) > -1) return;
    if (field.type === 'select-multiple') {
      Array.prototype.slice.call(field.options).forEach(function (option) {

        if (!option.selected) return;
        j_son[field.name] = option.value;
      });
      return;
    }
    if (['checkbox', 'radio'].indexOf(field.type) >-1 && !field.checked) return;
    j_son[field.name] = field.value;
  });
  return j_son;
};

//excel용 숫자를 컬럼(A,B,C...AA,AB,AC 등으로 변경하는 함수)
const num2XlsColumn = function(num){
  let str = '', temp;

  while (num > 0) {
    temp = (num - 1) % 26;
    str = String.fromCharCode(65 + temp) + str;
    num = (num - temp)/26 | 0;
  }
  return str || undefined;
};

//exceljs 라이브러리용 json을 엑셀로 저장.
const json2xls = function(filename, title, header, datas){
  if( typeof ExcelJS == "undefined" ) return false;

  filename = filename || "noname.xlsx";
  title    = title    || "제목을 입력하지 않았습니다.";
  header   = header   || [];
  datas    = datas    || [];
  filename = filename.replace(/[\*\?\:\\\/\[\]]/,'');
  title = title.replace(/[\*\?\:\\\/\[\]]/,'');

  const work_Book = new ExcelJS.Workbook();
  work_Book.creator   = "쿨스 ICT ("+window.location.protocol+"//"+window.location.hostname+")";
  work_Book.subject   = "쿨스 ICT - " + title;
  work_Book.title     = "쿨스 ICT - " + title;
  work_Book.description = "Kuls ICT - " + title;
  work_Book.keywords  = window.location.protocol+"//"+window.location.hostname+" - " + title;
  work_Book.catetory  = "쿨스 ICT";
  work_Book.company   = "쿨스 ICT (www.kuls.co.kr)";

  let work_Sheet = work_Book.addWorksheet(title),
  all_border = {
    top: {style:'thin', color: {argb:'FFAAAAAA'}},
    left: {style:'thin', color: {argb:'FFAAAAAA'}},
    bottom: {style:'thin', color: {argb:'FFAAAAAA'}},
    right: {style:'thin', color: {argb:'FFAAAAAA'}},
  },
  title_css = {
    font: {'size': 16, },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  thd_css = {
    border: all_border,
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFF2F2F2'}
    },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_css = {
    border: all_border,
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  dcol_css = {
    border: all_border,
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFEAEAEA'}
    },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_num_css = {
    border: all_border,
    numFmt: '#,##0',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_cnum_css = {
    border: all_border,
    alignment:{ vertical: 'middle', horizontal: 'center' },
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFFFC107'}
    },
  },
  col_price_css = {
    border: all_border,
    numFmt: '"₩" #,##0',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_price2_css = {
    border: all_border,
    numFmt: '"₩" #,##0.00',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  sttrow = 1,
  sttCol = 1,
  sttFld = num2XlsColumn( sttCol ),
  //endFld = num2XlsColumn( header.length + sttCol - 1 ),
  endnum = header.length + sttCol - 1;

  now_row = sttrow,
  ws_row = work_Sheet.getRow( now_row );
  ws_row.height = 30;
  ws_row.getCell(1).value = title;
  ws_row.getCell(1).style = title_css;


  work_Sheet.getRow(2);
  let haschild = false;
  if( typeof header[0] == "object" ){

    ws_row = work_Sheet.addRow(header.reduce( (obj,h)=>{
      if( h.columns && h.columns.length > 1 ){
        h.columns.forEach( v => obj.push(h.title) );
        haschild = true;
        endnum += h.columns.length - 1; //타이틀 row 의 merge 길이 추가
      }else{
        obj.push(h.title);
      }
      return obj;
    },[]));
  }else{
    ws_row = work_Sheet.addRow(header);
  }
  ws_row.eachCell((cell, idx) => {
    cell.style = thd_css;
  });

  let endFld = num2XlsColumn(endnum);
  work_Sheet.mergeCells(`${sttFld}${now_row}:${endFld}${now_row}`);

  let colfld = [];
  let nheader = [];

  if( haschild ){
    ws_row = work_Sheet.addRow(header.reduce( (obj,h)=>{
      if( h.columns && h.columns.length > 1 ){
        h.columns.forEach( v => {
          obj.push(v.title);
          colfld.push({key:v.key, width:v.width||15});
          nheader.push(v);
        } );
      }else{
        obj.push(h.title);
        colfld.push({key:h.key, width:h.width||15});
        nheader.push(h);
      }
      return obj;
    },[]));

    let nfld = 1;
    header.forEach(h => {
      let sttFld = num2XlsColumn(nfld);
      if( h.columns && h.columns.length > 1 ){
        nfld+=h.columns.length-1;
        let endFld = num2XlsColumn(nfld);
        work_Sheet.mergeCells(`${sttFld}3:${endFld}3`);
      }else{
        work_Sheet.mergeCells(`${sttFld}3:${sttFld}4`);
      }
      nfld++;
    });

    ws_row.eachCell((cell, idx) => {
      cell.style = thd_css;
    });

    header = nheader;
  }else{
    if( typeof header[0] == "object" ){
      colfld = header.map( v => { return { key:v.key, width:v.width||15 } } );
    }
  }
  work_Sheet.columns = colfld;

  datas.forEach(data => {
    data = Object.keys(data).reduce((ob,k, i) => {
      ob[k] = ((data[k]!==null && data[k]!==undefined) ?data[k]:'');
      switch( header[i-1]?.dcss ){
        case "num":
        case "cnum":
        case "price":
        case "price2":
          ob[k] = Number(ob[k]);
      }
      return ob;
    }, {});
    ws_row = work_Sheet.addRow(data||'');
    ws_row.eachCell((cell, idx) => {
      switch( header[idx-1]?.dcss ){
        case "bg":
          cell.style = dcol_css;
          break;
        case "num":
          cell.style = col_num_css;
          break;
        case "cnum":
          cell.style = col_cnum_css;
          break;
        case "price":
          cell.style = col_price_css;
          break;
        case "price2":
          cell.style = col_price2_css;
          break;
        default:
          cell.style = col_css;
      }
    });
  });

  work_Book.xlsx.writeBuffer().then((data) => {
    let blob = new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }),
    url = window.URL.createObjectURL(blob),
    anchor = document.createElement('a');
    anchor.href = url;
    anchor.download = filename;
    anchor.click();
    window.URL.revokeObjectURL(url);
  });
};

/*
 * Overview : 숫자(작은수 -> 큰수), 문자(그대로) 정렬
 */
function customSort(arr) {
  // 숫자로 변환 가능한 항목과 변환 불가능한 항목을 분리
  const numericValues = [];
  const nonNumericValues = [];

  arr.forEach(item => {
      // item을 trim한 후 숫자로 변환 가능한지 확인
      const trimmedItem = item.trim();
      if (!isNaN(parseInt(trimmedItem))) {
          numericValues.push(trimmedItem);
      } else {
          nonNumericValues.push(item);
      }
  });

  // 숫자로 변환 가능한 항목을 정렬
  numericValues.sort((a, b) => a - b);

  // 숫자로 변환 불가능한 항목을 앞에 두고, 그 뒤에 숫자 항목을 배치
  return nonNumericValues.concat(numericValues);
}

/*
 * Overview : json -> excel (filed값이 숫자, 문자 모두 있을때 dcss 적용)
 */
const json2xls_num = function(filename, title, header, datas){
  if( typeof ExcelJS == "undefined" ) return false;

  filename = filename || "noname.xlsx";
  title    = title    || "제목을 입력하지 않았습니다.";
  header   = header   || [];
  datas    = datas    || [];
  filename = filename.replace(/[\*\?\:\\\/\[\]]/,'');
  title = title.replace(/[\*\?\:\\\/\[\]]/,'');

  const work_Book = new ExcelJS.Workbook();
  work_Book.creator   = "쿨스 ICT ("+window.location.protocol+"//"+window.location.hostname+")";
  work_Book.subject   = "쿨스 ICT - " + title;
  work_Book.title     = "쿨스 ICT - " + title;
  work_Book.description = "Kuls ICT - " + title;
  work_Book.keywords  = window.location.protocol+"//"+window.location.hostname+" - " + title;
  work_Book.catetory  = "쿨스 ICT";
  work_Book.company   = "쿨스 ICT (www.kuls.co.kr)";

  let work_Sheet = work_Book.addWorksheet(title),
  all_border = {
    top: {style:'thin', color: {argb:'FFAAAAAA'}},
    left: {style:'thin', color: {argb:'FFAAAAAA'}},
    bottom: {style:'thin', color: {argb:'FFAAAAAA'}},
    right: {style:'thin', color: {argb:'FFAAAAAA'}},
  },
  title_css = {
    font: {'size': 16, },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  thd_css = {
    border: all_border,
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFF2F2F2'}
    },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_css = {
    border: all_border,
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  dcol_css = {
    border: all_border,
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFEAEAEA'}
    },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_num_css = {
    border: all_border,
    numFmt: '#,##0',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_cnum_css = {
    border: all_border,
    alignment:{ vertical: 'middle', horizontal: 'center' },
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFFFC107'}
    },
  },
  col_price_css = {
    border: all_border,
    numFmt: '"₩" #,##0',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_price2_css = {
    border: all_border,
    numFmt: '"₩" #,##0.00',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  sttrow = 1,
  sttCol = 1,
  sttFld = num2XlsColumn( sttCol ),
  //endFld = num2XlsColumn( header.length + sttCol - 1 ),
  endnum = header.length + sttCol - 1;

  now_row = sttrow,
  ws_row = work_Sheet.getRow( now_row );
  ws_row.height = 30;
  ws_row.getCell(1).value = title;
  ws_row.getCell(1).style = title_css;


  work_Sheet.getRow(2);
  let haschild = false;
  if( typeof header[0] == "object" ){

    ws_row = work_Sheet.addRow(header.reduce( (obj,h)=>{
      if( h.columns && h.columns.length > 1 ){
        h.columns.forEach( v => obj.push(h.title) );
        haschild = true;
        endnum += h.columns.length - 1; //타이틀 row 의 merge 길이 추가
      }else{
        obj.push(h.title);
      }
      return obj;
    },[]));
  }else{
    ws_row = work_Sheet.addRow(header);
  }
  ws_row.eachCell((cell, idx) => {
    cell.style = thd_css;
  });

  let endFld = num2XlsColumn(endnum);
  work_Sheet.mergeCells(`${sttFld}${now_row}:${endFld}${now_row}`);

  let colfld = [];
  let nheader = [];

  if( haschild ){
    ws_row = work_Sheet.addRow(header.reduce( (obj,h)=>{
      if( h.columns && h.columns.length > 1 ){
        h.columns.forEach( v => {
          obj.push(v.title);
          colfld.push({key:v.key, width:v.width||15});
          nheader.push(v);
        } );
      }else{
        obj.push(h.title);
        colfld.push({key:h.key, width:h.width||15});
        nheader.push(h);
      }
      return obj;
    },[]));

    let nfld = 1;
    header.forEach(h => {
      let sttFld = num2XlsColumn(nfld);
      if( h.columns && h.columns.length > 1 ){
        nfld+=h.columns.length-1;
        let endFld = num2XlsColumn(nfld);
        work_Sheet.mergeCells(`${sttFld}3:${endFld}3`);
      }else{
        work_Sheet.mergeCells(`${sttFld}3:${sttFld}4`);
      }
      nfld++;
    });

    ws_row.eachCell((cell, idx) => {
      cell.style = thd_css;
    });

    header = nheader;
  }else{
    if( typeof header[0] == "object" ){
      colfld = header.map( v => { return { key:v.key, width:v.width||15 } } );
    }
  }
  work_Sheet.columns = colfld;

  datas.forEach(data => {
    data = customSort(Object.keys(data)).reduce((ob,k, i) => {
      ob[k] = ((data[k]!==null && data[k]!==undefined) ?data[k]:'');
      
      switch( header[i]?.dcss ){
        case "num":
        case "cnum":
        case "price":
        case "price2":
          ob[k] = Number(ob[k]) === 0 ? "" : Number(ob[k]);
          break;
        default:
          ob[k] = ob[k];
          break;
      }
      return ob;
    }, {});
    ws_row = work_Sheet.addRow(data||'');
    ws_row.eachCell((cell, idx) => {
      switch( header[idx-1]?.dcss ){
        case "bg":
          cell.style = dcol_css;
          break;
        case "num":
          cell.style = col_num_css;
          break;
        case "cnum":
          cell.style = col_cnum_css;
          break;
        case "price":
          cell.style = col_price_css;
          break;
        case "price2":
          cell.style = col_price2_css;
          break;
        default:
          cell.style = col_css;
      }
    });
  });

  work_Book.xlsx.writeBuffer().then((data) => {
    let blob = new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }),
    url = window.URL.createObjectURL(blob),
    anchor = document.createElement('a');
    anchor.href = url;
    anchor.download = filename;
    anchor.click();
    window.URL.revokeObjectURL(url);
  });
};

//exceljs 라이브러리용 json을 엑셀로 저장.
const json2xls_report = function(filename, title, header, datas, total, din, add_title_height ){
  if( typeof ExcelJS == "undefined" ) return false;

  add_title_height = add_title_height||0; //추가높이
  filename = filename || "noname.xlsx";
  title    = title    || "제목을 입력하지 않았습니다.";
  header   = header   || [];
  datas    = datas    || [];
  filename = filename.replace(/[\*\?\:\\\/\[\]]/,'');
  title = title.replace(/[\*\?\:\\\/\[\]]/,'');

  const work_Book = new ExcelJS.Workbook();
  work_Book.creator   = "쿨스 ICT ("+window.location.protocol+"//"+window.location.hostname+")";
  work_Book.subject   = "쿨스 ICT - " + title;
  work_Book.title     = "쿨스 ICT - " + title;
  work_Book.description = "Kuls ICT - " + title;
  work_Book.keywords  = window.location.protocol+"//"+window.location.hostname+" - " + title;
  work_Book.catetory  = "쿨스 ICT";
  work_Book.company   = "쿨스 ICT (www.kuls.co.kr)";

  let work_Sheet = work_Book.addWorksheet(title),
  all_border = {
    top: {style:'thin', color: {argb:'FFAAAAAA'}},
    left: {style:'thin', color: {argb:'FFAAAAAA'}},
    bottom: {style:'thin', color: {argb:'FFAAAAAA'}},
    right: {style:'thin', color: {argb:'FFAAAAAA'}},
  },
  title_css = {
    font: {'size': 16, },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  thd_css = {
    border: all_border,
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFF2F2F2'}
    },
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_css = {
    border: all_border,
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_num_css = {
    border: all_border,
    numFmt: '#,##0',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_cnum_css = {
    border: all_border,
    alignment:{ vertical: 'middle', horizontal: 'center' },
    fill: {
      type: 'pattern',
      pattern: 'solid',
      fgColor: {argb: 'FFFFC107'}
    },
  },
  col_price_css = {
    border: all_border,
    numFmt: '"₩" #,##0',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  col_price2_css = {
    border: all_border,
    numFmt: '"₩" #,##0.00',
    alignment:{ vertical: 'middle', horizontal: 'center' },
  },
  sttrow = 1,
  sttCol = 1,
  sttFld = num2XlsColumn( sttCol ),
  endnum = header.length + sttCol - 1,
  endFld = num2XlsColumn( header.reduce( (sum, h) => { return sum + (( h.columns && h.columns.length > 1 ) ? h.columns.length : 1); }, 1 ) - 1 ),

  now_row = sttrow,
  ws_row = work_Sheet.getRow( now_row );
  if( din ){
    ws_row.height = 44 + add_title_height;
  }else{
    ws_row.height = 60 + add_title_height;
  }

  ws_row.getCell(sttCol).value = title;
  ws_row.getCell(sttCol).style = title_css;
  work_Sheet.mergeCells(`${sttFld}${now_row}:${endFld}${now_row}`);
  if( din ){
    now_row++;
    ws_row = work_Sheet.getRow( now_row );
    let todt = new Date();
    ws_row.getCell(sttCol).value = '작성일: '+todt.getFullYear()+'년 '+('0'+(todt.getMonth()+1)).substr(-2)+'월 '+('0'+todt.getDate()).substr(-2)+'일';
    work_Sheet.mergeCells(`${sttFld}${now_row}:${endFld}${now_row}`);
  }
  now_row++;

  work_Sheet.getRow(now_row);
  let haschild = false;
  if( typeof header[0] == "object" ){
    ws_row = work_Sheet.addRow(header.reduce( (obj,h)=>{
      if( h.columns && h.columns.length > 1 ){
        h.columns.forEach( v => obj.push(h.title) );
        haschild = true;
        endnum += h.columns.length - 1; //타이틀 row 의 merge 길이 추가
      }else{
        obj.push(h.title);
      }
      return obj;
    },[]));
  }else{
    ws_row = work_Sheet.addRow(header);
  }
  ws_row.eachCell((cell, idx) => {
    cell.style = thd_css;
  });

  let colfld = [];
  let nheader = [];
  if( haschild ){
    ws_row = work_Sheet.addRow(header.reduce( (obj,h)=>{
      if( h.columns && h.columns.length > 1 ){
        h.columns.forEach( v => {
          obj.push(v.title);
          colfld.push({key:v.key, width:v.width||15});
          nheader.push(v);
        } );
      }else{
        obj.push(h.title);
        colfld.push({key:h.key, width:h.width||15});
        nheader.push(h);
      }
      return obj;
    },[]));

    let nfld = 1;
    header.forEach(h => {
      let sttFld = num2XlsColumn(nfld);
      if( h.columns && h.columns.length > 1 ){
        nfld+=h.columns.length-1;
        let endFld = num2XlsColumn(nfld);
        work_Sheet.mergeCells(`${sttFld}4:${endFld}4`);
      }else{
        work_Sheet.mergeCells(`${sttFld}4:${sttFld}5`);
      }
      nfld++;
    });

    ws_row.eachCell((cell, idx) => {
      cell.style = thd_css;
    });

    header = nheader;
  }else{
    if( typeof header[0] == "object" ){
      colfld = header.map( v => { return { key:v.key, width:v.width||15 } } );
    }
  }
  work_Sheet.columns = colfld;

  let totlen = 0, imgw;  //imgw 는 결재이미지 크기의 비율
  if( typeof header[0] == "object" ){
    work_Sheet.columns = header.map( v => { let tlen = v.width||15; totlen += tlen; return { key:v.key, width:tlen } } );
  }

  if( add_title_height ){
    imgw = 55.3;
  }else{
    imgw = 36.7;
  }

  let collen = 0;
  if( total ){
    let snum = 4;
    if( din ){
      snum = 5;
    }

    let totrow = header.map( (v,i) => v.sum===true ? {formula: 'SUM('+num2XlsColumn(i+1)+(snum)+':'+num2XlsColumn(i+1)+(datas.length+snum-1)+')'}:(v.sum||'') );
    datas.push(totrow);
  }
  datas.forEach((data,i) => {
    if( !Array.isArray(data) ){
      data = Object.keys(data).reduce( (oo,kk) => { oo[kk] = (data[kk] && data[kk]!==0)?data[kk]:''; return oo; } , {} );
    }
    ws_row = work_Sheet.addRow(data);
    let ovr = true;
    ws_row.eachCell((cell, idx) => {
      if( !i ){
        totlen -= header[idx-1].width||15;
        if( totlen > imgw ){
          collen +=1;
        }else if( ovr ){
          let mg = (header[idx-1].width - imgw + totlen)/header[idx-1].width;
          collen += mg;
          ovr = false;
        }
      }
      switch( header[idx-1]?.format ){
        case "num":
          cell.style = col_num_css;
          break;
        case "cnum":
          if( i < (datas.length-1) && data[header[idx-1].key] ){ //해더 포맷이 cnum 이고 값이 존재하는것만
            cell.style = col_cnum_css;
          }else{
            cell.style = col_css;
          }
          break;
        case "price":
          cell.style = col_price_css;
          break;
        case "price2":
          cell.style = col_price2_css;
          break;
        default:
          cell.style = col_css;
      }
    });
  });

  work_Book.appImage = work_Book.addImage({
    base64: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASYAAABRCAIAAADw9pxAAAADy0lEQVR42u2dgW7jIBBE4///6F4lS5YvjYmBNTs7eiO1Sk8xOwO8Qoh72V4IoYXafr9+fn5i2tq2qKZy+qK4f7Lo6zcLyPn4J4u+QM7KP1n0JYpcYBd3NRU7tLkTpTf48fh8VdZABF4bHmSy2UzkzsO867i2N0lUU2M9GJXiY2t/m30uS3iHRNGbjlxgqGTkrp48gFxIU7FDOzYei8fiCvL92smBmOyNkG45ZvjwVI8NpYvc/uBma1FNhSB3/lEfubcnN6bXQNFE5K7GvXdqhYfSRa7iKjc5X19JG8v2lOqqroNcoJyRO+8BJpEbayp2WpTYWJ67a5fHKhcoK+Te/qXi8cnrhPd8a7knhFG/NY7HWccnjc3CWSknurxJMFW33XslNpbtijZvEjwkH+SyJOU/9oVlukDuuCQTucBf6letRR3DLEsxaWbs8gWrawpy81MiPFQ+coFJ5psaRi58kqVfPtzIEytS+rjEbrBHkIsKA3LnJ9952uKb10AuPFQLuYFjQDaW8ymipHDDV1RvKGwso0J1rHJ37quQfZl7vztK+yeLvvqQC1/l1FTdP1n0dRe5m7cyVe+a6v7Joq/vyL3diH2o8fLveAu13PcjWroTshhnubxZqY0Wq5y4yKIp7j6x8k8WfX1BrvdstHrXVPdPFn0lvxWupur+yaIvVjkr/2TR13fkFty9oaPq/smiL1Y5K/9k0Rcnllb+yaIvkLPyTxZ9gZyVf7LoC+Ss/JNFXyBn5Z8s+gI5K/9k0RfIWfkni75Azso/WfQFclb+yaIvkLPyTxZ9gZyVf7LoC+Ss/JNFXyBn5Z8s+gI5K/9k0RfIWfkni75Azso/WfQFclb+yaIvkLPyTxZ9gZyVf7LoC+Ss/JNFXyBn5Z8s+gI5K/9k0RfIWfkni75Azso/WfTFZxJY+SeLvvqQO5KDnL7IoqlL5LZPn5kKcoVEFk31fQwIyBUSWTQFclb+yaKvbuSOxyAnLrJoqoXcnvOcllWukMiiKZCz8k8WfbVOLBukNZDbWzvjWuj7nkLBCVmMs3xA7i9Rbyseq5y+yKIp3gq38k8WfYGclX+y6It7LK38k0VfVf+S4KFCi4f20XJk0SwHcjn+F5Qji2a5ksg9V2Xl0D5diyyatUAuwf+aWmTRrFUPOY8NTPWOIstMCZBb6n9ZIbJoFiqGXPX2qUIVkFvaPlWoUgk5jw2M2R6JLAOFQM6tBFk0SxyFaiDnsbUwO+wmy1gtkFtXhWmqWQvk0lTdP1n0BXJW/smiL5Cz8k8WfW3b//8rM0Loaf0DdS6S6P1Z65wAAAAASUVORK5CYII=",
    extension: 'png',
  });

  work_Book.appImage2 = work_Book.addImage({
    base64: "data:image/png;base64,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",
    extension: 'png',
  });

  work_Book.appImage3 = work_Book.addImage({
    base64: "data:image/png;base64,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",
    extension: 'png',
  });

  if( add_title_height === 0 ) {
    work_Sheet.addImage(work_Book.appImage, {
      tl: {col: collen, row: 0},
      ext: {width: 294, height: 81}
    });
  }else{
    // work_Sheet.addImage(work_Book.appImage2, {
    //   tl: {col: collen, row: 0},
    //   ext: {width: 395, height: 114}
    // });
    work_Sheet.addImage(work_Book.appImage3, {
      tl: {col: collen, row: 0},
      ext: {width: 443, height: 131}
    });
  }

  work_Book.xlsx.writeBuffer().then((data) => {
    let blob = new Blob([data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }),
    url = window.URL.createObjectURL(blob),
    anchor = document.createElement('a');
    anchor.href = url;
    anchor.download = filename;
    anchor.click();
    window.URL.revokeObjectURL(url);
  });
};

const json2xls_report_date = function(filename, title, header, datas, total, add_title_height ){
  return json2xls_report(filename, title, header, datas, total, true, add_title_height );
}


//exceljs 라이브러리용 엑셀을 Json으로 반환
const xls2json = async function(tgt, options){
  let xlsfile = tgt.files[0];
  if( !xlsfile ){
    kuls_alert("엑셀 파일을 등록해 주세요."); return;
  }
  if( !options ) options = {};

  let jsonData = [], //엑셀내용이 저장되는 변수
  workbook = new ExcelJS.Workbook();
  await workbook.xlsx.load( xlsfile );

  /*파일 읽어오는 위치 지정*/
  let rowIdx = options.rowIdx === undefined ? 2 : Number(options.rowIdx),
  cellIdx = options.cellIdx === undefined ? 0 : Number(options.cellIdx),
  ws_keys = workbook._worksheets.keys(),
  worksheet = workbook.getWorksheet(ws_keys[0]),
  dataSheet = worksheet._rows.filter( (row,idx) => idx >= rowIdx );
  if( !dataSheet.length ){
    kuls_alert("데이터가 존재하지 않습니다."); return;
  }

  //병합(Merge)정보가 필요할댄 worksheet._merges 를 이용하면 된다. 필요할때 추가요망.

  dataSheet.forEach( (row, ridx) => {
    let readRow = ridx + rowIdx,
    rowJson = [],
    cellval;
    row._cells.forEach( (cell, cidx) => {
      if( cidx < cellIdx ) return;

      switch( cell.type ){
        case 0 : //내용없음(에러셀)
        case 1 : //병합셀내용 => cell.isMerged 로 확인해야 하지만...gogo
          cellval = "";
          break;
        case 4 : //날짜
          cellval = cell.value.getFullYear() +'-'+ String((cell.value.getMonth()+1)).padStart(2,0) +'-'+ String(cell.value.getDate()).padStart(2,0);
          break;
        case 5 : //object
          cellval = cell.value.text;
          break;
        case 2 : //숫자
        case 3 : //문자
        default :
          cellval = cell.text;
      }

      rowJson.push(cellval);
    } );
    jsonData.push(rowJson);
  })

  if( options.func ){ //options.func 는 콜백방식으로 사용하려고 추가해둔것, async..await로 쓰는게 나을것 같아서 미사용
    options.func(jsonData);
  }
  return jsonData;
};


const formSetVal = function( tgt, tag ){ //form 기본(초기)값 처리용
  /** Attribute 가 코딩으로 직접적으로 명시된 태그에만 동작함으로 주의필요. "[data-defval]"
   * Attribute를 코딩으로 입력하지 않은곳에서 사용하려면 attr("data-defval","") 로 data-defval Attribute를 추가한후 사용한다.
   */
  tgt = tgt || document;

  if( !tag || tag == "select" ) {
    /*
    * select 박스 기본값 selected 처리용
    * */
    jQuery(tgt).find("select").each(function(){
      if( jQuery(this).data("defval") !== undefined ){
        jQuery(this).attr("data-defval", jQuery(this).data("defval"));
      }
    });

    jQuery(tgt).find("select[data-defval]").each(function(){ //Select Box 현재값 지정
      let _this = this,
      selval = jQuery(this).data("defval");
      if( typeof selval != "object" ){
        selval = [selval];
      }
      selval.forEach( v => {
        _this.querySelectorAll("option").forEach( opt => {
          if( opt.value == v ){
            opt.selected = true;
          }
        });
      });
    });
  }

  if( !tag || tag == "radio" ) {
    /*
    * input radio 기본값 checked 처리용. 유일 선택 기준.
    * */
    jQuery(tgt).find("[type=radio]").each(function(){
      if( jQuery(this).data("defval") !== undefined ){
        jQuery(this).attr("data-defval", jQuery(this).data("defval"));
      }
    });

    jQuery(tgt).find("[type=radio][data-defval]").each(function(){ //Input:radio 현재값 지정
      if( jQuery(this).val() == trim(jQuery(this).data("defval")) ){
        jQuery(this).prop("checked",true);
      }
    });
  }

  if( !tag || tag == "date" ) {
    /*
    * input radio 기본값 checked 처리용. 유일 선택 기준.
    * */
    jQuery(tgt).find("[type=date]").each(function(){ //Input:date 현재값 지정
      if( jQuery(this).data("defval") !== undefined ) {
        if (jQuery(this).val() !== undefined) {

          function dateFormat(date) {
            let month = date.getMonth() + 1;
            let day = date.getDate();

            month = month >= 10 ? month : '0' + month;
            day = day >= 10 ? day : '0' + day;

            return date.getFullYear() + '-' + month + '-' + day;
          }

          jQuery(this).val(dateFormat(new Date(jQuery(this).data("defval"))));
        }
      }
    });
  }

  if( !tag || tag == "checkbox" ) {
    /*
    * input checked 기본값 checked 처리용.
    * */
    jQuery(tgt).find("[type=checkbox]").each(function(){
      if( jQuery(this).data("defval") !== undefined ){
        jQuery(this).attr("data-defval", jQuery(this).data("defval"));
      }
    });

    jQuery(tgt).find("[type=checkbox][data-defval]").each(function(){ //Input:checkbox 현재값 지정
      jQuery(this).prop("checked",false);

      //if( /(\[|\{)/.test(chkval) ) chkval = JSON.parse(chkval);

      let chkval = jQuery(this).data("defval");
      if( typeof chkval == "object" ){
        if( chkval.indexOf(jQuery(this).val()) !== -1 ){
          jQuery(this).prop("checked",true);
        }
      }else{
        if( jQuery(this).val() == trim(chkval) ){
          jQuery(this).prop("checked",true);
        }
      }
    });
  }

  if( !tag ){
    /*
    *  기타 input / textarea 기본값 처리용
    * */
    jQuery(tgt).find("input:not([type=checkbox]):not([type=radio]):not([type=date]), textarea").each(function(){
      if( jQuery(this).data("defval") !== undefined ){
        jQuery(this).attr("data-defval", jQuery(this).data("defval"));
      }
    });

    jQuery(tgt).find("input[data-defval]:not([type=checkbox]):not([type=radio]):not([type=date]), textarea[data-defval]").each(function(){ //Select Box 현재값 지정
      if( !jQuery(this).data("defval") || jQuery(this).data("defval") == "null" ){
        jQuery(this).data("defval", "");
      }
      jQuery(this).val(trim(jQuery(this).data("defval")));
    });
  }
};

document.addEventListener("click", function(e) {
  if(e.target.classList.contains('btnFindAddr')){
    if( daum ){
      new daum.Postcode({
        theme: {
          searchBgColor: "#ECECEC", //검색창 배경색
          queryTextColor: "#000" //검색창 글자색
        },
        oncomplete: function(data) {
          let zipcode = "", address = "";
          if( data ){
            switch( data.userSelectedType ){
              case "R": //도로명 클릭
                address = data.roadAddress;
              break;
              case "J": //지번 클릭
                address = data.jibunAddress;
              break;
            }
            zipcode = data.zonecode;
            document.querySelector(e.target.attributes['data-zipcode'].value).value = zipcode;
            document.querySelector(e.target.attributes['data-address'].value).value = address;
          }
        }
      }).open({popupTitle:'쿨스 우편번호 검색', popupKey:'Kuls'});
    }
  }
});
// document.querySelectorAll(".btnFindAddr").forEach(tgt => tgt.addEventListener("click",function(){
//   if( daum ){
//     new daum.Postcode({
//       theme: {
//         searchBgColor: "#ECECEC", //검색창 배경색
//         queryTextColor: "#000" //검색창 글자색
//       },
//       oncomplete: function(data) {
//         let zipcode = "", address = "";
//         if( data ){
//           switch( data.userSelectedType ){
//             case "R": //도로명 클릭
//               address = data.roadAddress;
//             break;
//             case "J": //지번 클릭
//               address = data.jibunAddress;
//             break;
//           }
//           zipcode = data.zonecode;
//           document.querySelector(tgt.attributes['data-zipcode'].value).value = zipcode;
//           document.querySelector(tgt.attributes['data-address'].value).value = address;
//         }
//       }
//     }).open({popupTitle:'쿨스 우편번호 검색', popupKey:'Kuls'});
//   }
// }));

let vnLoad_dupPrev = false;
const vnLoad = function( tgtsql, url, selector, func ){ //jquery.load 대체

  if( vnLoad_dupPrev ) return;
  // {
  //   console.log('POP Prevent');
  //   return;
  // }
  vnLoad_dupPrev = true;
  fetch( url )
    .then( (response) => response.text() )
    .then( (bodyHtml) => {
      let domhtml = document.createElement('div');
      domhtml.innerHTML = bodyHtml;
      let usehtml = "";
      if(selector){
        usehtml = domhtml.querySelector(selector).innerHTML;
      }else{
        usehtml = domhtml.innerHTML;
      }
      vnLoad_dupPrev = false;
      if( func ){
        func(usehtml);
      }else{
        let tgtdom = document.querySelector(tgtsql);
        tgtdom.innerHTML = usehtml;
      }
    } );
};

/*
* Tree Row 정리
* */
const tree_by_parent = ( row, cd_fld, pcd_fld, pcd_val ) => {
  return row.filter( r => r[cd_fld] && pcd_val == (r[pcd_fld]||'') ).map( rc => {
    rc['key'] = rc['DEPT_CD'];
    rc['title'] = rc['DEPT_NM'];
    rc['children'] = tree_by_parent(row, cd_fld, pcd_fld, rc[cd_fld]);
    if( rc['children'].length ){
      rc['folder'] = true;
    }
    return rc;
  } );
}


/*
* 모두 체크 처리
* */
jQuery("body").on("click",".allsel",function(){
  let tgt = jQuery(this).data("tgt"),
  notchkbox = jQuery(this).prop("tagName").toUpperCase() != "INPUT" || jQuery(this).attr("type").toUpperCase() != "CHECKBOX";

  if( jQuery(this).is(":checked") || notchkbox ){
    jQuery("input[type=checkbox][name^="+tgt+"]").prop("checked", true );
  }else if( !notchkbox && !jQuery(this).is(":checked") ){
    jQuery("input[type=checkbox][name^="+tgt+"]").prop("checked", false );
  }
});

/**
 * Form 기본(초기)값 세팅 실행
 */
jQuery(document).ready(function(){
  formSetVal(document);
});


/**
 * Inline tinymce
 */
let webeditor = document.querySelectorAll(".inline_mceedit");
let tinyboard;
if (webeditor.length && tinymce) {
  tinyobj = tinymce.init({
    selector: '.inline_mceedit',
    plugins: 'print preview searchreplace code autolink directionality visualblocks visualchars fullscreen image link media table charmap hr pagebreak nonbreaking anchor toc insertdatetime advlist lists imagetools textpattern help',
    toolbar: ['fontselect | fontsizeselect | bold italic strikethrough forecolor backcolor','link image media table| alignleft aligncenter alignright alignjustify  | numlist bullist outdent indent'],

    forced_root_block: 'div',
    //force_br_newlines : true,
    //force_p_newlines : true,
    //visualblocks_default_state: true,

    image_advtab: true,
    importcss_append: true,
    relative_urls: false, //상대경로 사용안함
    remove_script_host: false, //동일 도메인인경우 도메인제거 사용금지
    menubar: true,
    inline: true,
    image_caption: true,
    //content_css: ['/common/css/main.css'],
    content_style: '.mce-content-body {font-family:Gulim; max-width:945px; margin:0 auto; border-left:solid 1px #F4F4F4; border-right:solid 3px #F4F4F4; padding:10px;}',
    language: 'ko_KR',
    theme: 'silver',
    branding: false,
    font_formats: "맑은고딕=Malgun Gothic;굴림=Gulim;굴림체=GulimChe;새굴림=New Gulim;돋움=Dotum;돋움체=DotumChe;바탕=Batang;바탕체=BatangChe;궁서=Gungsuh;궁서체=GungsuhChe;Andale Mono=andale mono,monospace;Arial=arial,helvetica,sans-serif;Arial Black=arial black,sans-serif;Book Antiqua=book antiqua,palatino,serif;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier,monospace;Georgia=georgia,palatino,serif;Helvetica=helvetica,arial,sans-serif;Impact=impact,sans-serif;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco,monospace;Times New Roman=times new roman,times,serif;Trebuchet MS=trebuchet ms,geneva,sans-serif;Verdana=verdana,geneva,sans-serif;Webdings=webdings;Wingdings=wingdings,zapf dingbats",
    setup: function (editor) {
      editor.on('init', function (e) {
        tinyboard = tinymce.editors.contents || tinymce.editors[0];
        tinyboard.contentDocument.addEventListener("drop", e => {
          let files = e.dataTransfer.files;
          if (files.length) {
            e.stopPropagation();
            e.preventDefault();
            //Array.from(files).forEach(file => fileuploader.addFile(URL.createObjectURL(file)));
            for (let a = 0; a < files.length; a++) {
              let formData = new FormData();
              formData.append('ufile', files[a], files[a].name);
              fileuploader.addFile(formData.get('ufile'));
            }
          }
        });
      });
    }
    // setup: function(editor){ //줄바꿈 금지 1줄 에디터
    //   editor.on('keydown', function(event){
    //     if(event.keyCode == 13){
    //       event.preventDefault();
    //       event.stopPropagation();
    //       return false;
    //     }
    //   });
    // },
  });
}