;
/*************************************************************
 *
 * Copyright (c) 2024 ysrock Co., Ltd.	<info@ysrock.co.jp>
 * Copyright (c) 2024 Yasuo Sugano	<sugano@ysrock.co.jp>
 *
 * Version	: 1.2.0
 * Update	  : 2024.11.27
 *
 ************************************************************/
'use strict';
(function($){
  $(document).ready(function(){
    // UUIDを各種に付加
    uuidFunc.ready();
    // メインメニュー
    navFunc.ready();
  });


  /**
   * UUID
   */
  let uuidFunc = (function(){
    return{
      'ready': function(){
        // 現在のURLからuuidを取得する
        this.uuid = this.get();
        
        // アンカーリンクにUUIDを加える
        this.repHref();
        // フォームにUUIDを加える
        // this.reForm();
      },
      'get': function(){
        return location.search.match(/uuid=([\w\-]+)/) ? RegExp.$1 : "";
      },
      'repHref': function(){
        $('a').each(function(){
          if( !$(this).attr('href') ) return true;
          let url = $(this).attr('href');
          if(url.match(/^#/)) return true;
          if(url.match(/uuid=/)) return true;
          if(url.match(/\/{2}/)) return true;
          let href = url + (url.match(/\?/) ? "&" : "?") + "uuid=" + uuidFunc.uuid;
          $(this).attr('href', href );
        });
      },
      'repForm': function(){

      }
    }
  })();


  /**
   * メインメニュー
   */
  let navFunc = (function(){
    return{
      'ready': function(){
        this.appendLogout();
        this.menuOpen();
        this.scrollTop();
        if( !window.matchMedia('(max-width: 640px)').matches ){
         this.menuListHover();
        }else{
          this.menuListTouch();
        };
      },
      'appendLogout': function(){
        $('#main-nav > div.wrap > ul').after('<a href="./?logout" class=\"logout\">ログアウト</a>');
      },
      'menuOpen': function(){
        $(document).on('click', '#main-nav > div.wrap > div.header > span.menu', function(){
          $(this).closest('div.wrap').toggleClass('open');
          $('body').toggleClass('overflowY_mainNav');
        });
      },
      'scrollTop': function(){
        $(window).scroll(function(){
          if( $(this).scrollTop() >= 200 ) $('#main-nav > div.wrap > div.header > span.top').css('display', 'block');
          else $('#main-nav > div.wrap > div.header > span.top').css('display', 'none');
       });
        $(document).on('click', '#main-nav > div.wrap > div.header > span.top', function(){
          $('html, body').animate({ 
            scrollTop: 0
          }, 300);
        });
      },
      'menuListHover': function(){
        $('#main-nav > div.wrap > ul li.child-nav').hover(function(){
          // ウィンドウのサイズ
          let windowHeight = $(window).height();
          // メニューない（スクロール無視）のTOPからの位置
          let liTop = $(this).offset().top - $(window).scrollTop();
          // ウィンドウの上半分
          if (liTop / windowHeight <= 0.5) {
            $(this).children('ul').css('top', liTop);
            $(this).children('ul').css('bottom', 'initial');
          } else {
            $(this).children('ul').css('bottom', ( windowHeight - liTop - $(this).height() ) );
            $(this).children('ul').css('top', 'initial');
          };
          // サブサブメニュー
          if ($(this).parent().css('left').match(/^(\d+)px/)) {
            $(this).children('ul').css('left', Number(RegExp.$1) + Number($(this).width()) - 5);
          };
        });
      },
      'menuListTouch': function(){
        $('#main-nav > div.wrap > ul li.child-nav > a').on('touchend', function(e){
          e.preventDefault();
          $(this).parent().toggleClass('open');
        });
      }
    }
  })();



  /**
   * 非同期通信
   */
  window['Ajax'] = function(options, cbDone, cbFail, cbAlways) {
    if (cbDone === undefined) cbDone = () => {};
    if (cbFail === undefined) cbFail = () => {};
    if (cbAlways === undefined) cbAlways = () => {};
    let ajax = $.fn.ysAjax();
    for (let key in options) ajax.options[key] = options[key];
    return $.ajax( ajax.options ).done(cbDone).fail(cbFail).always(cbAlways);
    // return ajax;
  };
  
})(jQuery);



(() => {
  window.addEventListener('load', () => {
  });
});





/**
 * Vue3
 */
window['Vue3'] = (function(){
  return{
    'loaderOption': function(){
      return{
        moduleCache: { vue: Vue },
        getFile(url){
          url = /.*?\.js|.mjs|.css|.less|.vue$/.test(url) ? url : `${url}.vue`;
          url += "?" + Math.random();
          const type = /.*?\.js|.mjs$/.test(url) ? ".mjs" : /.*?\.vue$/.test(url) ? ".vue" : /.*?\.css$/.test(url) ? ".css" : ".vue";
          const getContentData = (asBinary) => fetch(url).then((res) => !res.ok ? Promise.reject(url) : asBinary ? res.arrayBuffer() : res.text() );
          return { getContentData: getContentData, type: type };
        },
        addStyle(textContent) {
          let styleElement = document.createElement("style");
          document.head.insertBefore(
            Object.assign(styleElement, { textContent }),
            document.head.getElementsByTagName("style")[0] || null
          );
        },
        handleModule(type, getContentData, path, options) {
          switch (type) {
            case ".css":
              return options.addStyle(getContentData(false));
            case ".less":
              console.error(".......");
          }
        },
        log(type, ...args) { console.log(type, ...args); }
      }
    }
  }
})();

  
/**
 * 分割アップロード
 *  window['chunkedUpload'](file, endpoint, optionObj, cbObj);
 *    @param (file) file
 *    @param (string) endpoint
 *    @param (?object) callback
 *      (?function) next(resJson, closure)
 *      (?function) done(resJson, closure)
 *    @param (?object) optionObj
 *      (?string) chunkSize = 1048576
 *    @param (?object) headerObj
 *    return (string) serverPath
 */
window['chunkedUpload'] = (...args) => chunkedUploadClosure.execute(...args);
const chunkedUploadClosure = (() => {
  return {
  cbObj: null,
  chunkObj: null,
  headerObj: null,
  execute: (file, endpoint, cbObj, optionObj, headerObj) => {
    if (!chunkedUploadClosure.initialize(file, endpoint, cbObj, optionObj, headerObj)) return;
    chunkedUploadClosure.readFile(0, chunkedUploadClosure.headerObj);
  },
  initialize: (file, endpoint, cbObj, optionObj, headerObj) => {
    if (chunkedUploadClosure.chunkObj !== null) {
      console.debug([ "window['chunkedUpload']", '_initialize', '_chunkObj is not null.' ]);
      return;
    };
    if (file === undefined) {
      console.debug([ "window['chunkedUpload']", '_initialize', 'file is undefined.' ]);
      return;
    };
    if (!endpoint) {
      console.debug([ "window['chunkedUpload']", '_initialize', 'endpoint is undefined.' ]);
      return;
    };
    chunkedUploadClosure.cbObj = cbObj === null || typeof(cbObj) != "object" ? {} : cbObj;
    if (optionObj === null || typeof(optionObj) != "object") optionObj = {};
    chunkedUploadClosure.chunkObj = {
      file: file,
      endpoint: endpoint,
      chunkSize: "chunkSize" in optionObj ? optionObj.chunkSize : 1048576
    };
    chunkedUploadClosure.headerObj = typeof(headerObj) != "object" ? {} : headerObj;
    chunkedUploadClosure.headerObj['chunk-uuid'] = chunkedUploadClosure.getUuid();
    chunkedUploadClosure.headerObj['chunk-denominator'] = Math.ceil(file.size / chunkedUploadClosure.chunkObj.chunkSize);
    chunkedUploadClosure.headerObj['chunk-mime'] = file.type;
    chunkedUploadClosure.headerObj['chunk-counter'] = null;
    return true;
  },
  getUuid: function() {
    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c){
      let r = Math.random() * 16 | 0, v = c == "x" ? r : r & 3 | 8;
      return v.toString(16);
    });
  },
  readFile: (counter, headerObj) => {
    headerObj['chunk-counter'] = counter;
    const begin = Number(headerObj['chunk-counter']) * Number(chunkedUploadClosure.chunkObj.chunkSize);
    const end = Number(begin) + Number(chunkedUploadClosure.chunkObj.chunkSize);
    const FR = new FileReader();
    FR.onload = (e) => {
      chunkedUploadClosure.fetch(e.target.result, e.target.headerObj);
    };
    FR.headerObj = headerObj;
    FR.readAsArrayBuffer(chunkedUploadClosure.chunkObj.file.slice(begin, end));
  },
  fetch: (data, headerObj) => {
    if (headerObj === undefined) headerObj = {};
    if ('Content-Type' in headerObj === undefined) headerObj['Content-Type'] = "application/octet-stream";
    fetch(chunkedUploadClosure.chunkObj.endpoint, {
      method: 'POST',
      headers: headerObj,
      body: data,
      mode: 'cors',
      credentials: 'include',
      cache: 'no-cache'
    })
    .then(response => {
      if (!response.ok) throw new Error("Network response was not ok.");
      const result = response.json();
      result.then(resJson => {
        if ('next' in resJson) chunkedUploadClosure.next(resJson);
        if ('file' in resJson) chunkedUploadClosure.done(resJson);
      });
    })
    .catch(error => {
      console.error([ "window['chunkedUpload']", 'fetch error', error ]);
      reject(error);
    });
  },
  next: (resJson) => {
    if ('next' in chunkedUploadClosure.cbObj) {
      if (!chunkedUploadClosure.cbObj.next(resJson, chunkedUploadClosure)) return;
    };
    chunkedUploadClosure.readFile(resJson.next, chunkedUploadClosure.headerObj);
  },
  done: (resJson) => {
    chunkedUploadClosure.chunkObj = null;
    chunkedUploadClosure.headerObj = null;
    if ('done' in chunkedUploadClosure.cbObj) chunkedUploadClosure.cbObj.done(resJson, chunkedUploadClosure);
    chunkedUploadClosure.cbObj = null;
  },
  };
})();


/**
 * 非同期通信
 *  @param url (string)
 *  @param headerObj (object)
 *  @param cbResolve (function)
 *  @param cbReject (function)
 */
window['ysFetch'] = (...args) => fetchClosure.execute(...args);
const fetchClosure = (() => {
  return {
    execute: function (url, headerObj, cbResolve, cbReject) {
      fetch(url, this.header(headerObj))
      .then(response => this.response(response, cbResolve))
      .catch(error => this.error(error, cbReject));
    },
    header: function (inputObj) {
      const fetchObj = {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        cache: "no-cache"
      };
      for (let key in inputObj) {
        if (key == "headers") fetchObj['headers'] = this.joinHeaders(fetchObj['headers'], inputObj['headers']);
        else fetchObj[key] = inputObj[key];
      };
      return fetchObj;
    },
    response: function (response, cbResolve) {
      console.debug([ 'fetch response', response ]);
      if (!response.ok) throw new Error("Network response was not ok.");
      if (typeof cbResolve == "function") cbResolve(response);
    },
    error: function (error, cbReject) {
      console.error([ 'fetch error', error ]);
      if (typeof cbReject == "function") cbReject(response);
    },

    joinHeaders: function (fetchObj, inputObj) {
      for (let key in inputObj) fetchObj[key] = inputObj[key];
      return fetchObj;
    },
  };
})();
