;
/*************************************************************
 *
 * Copyright (c) 2023 ysrock Co., Ltd.	<info@ysrock.co.jp>
 * Copyright (c) 2023 Yasuo Sugano	<sugano@ysrock.co.jp>
 *
 * Version	: 1.3.0
 * Update	  : 2023.09.28
 *
 ************************************************************/
'use strict';
(function($){

  let vSelectObj = {
    activeSelect: null
  };

  /**
   * 検索型セレクトボックス
   */
  $.fn.vSelect = function( opts ) {
    if (opts === undefined) opts = {};
    /*****
     *
     * noMatchText
     *    Type: String
     *    Default: "一致しません"
     *
     * ifNoMatchThenAddOption（完全一致がない場合項目を追加する）
     *    Type: Boolean
     *    Default: false
     *
     * addOptionTxt（項目を追加する時の文言）
     *    Type: String
     *    Default: null
     *
     * maxHeight（疑似プルダウンの高さ）
     *    Type: Number
     *    Default: false
     *
     * maxImageSize（疑似プルダウンに表示する画像のサイズ。max-width・max-height）
     *    Type: Number
     *    Default: 30px
     *
     *
     *****/
    const noMatchText = 'noMatchTxt' in opts === false ? "一致しません" : opts['noMatchTxt'];
    const ifNoMatchThenAddOption = 'ifNoMatchThenAddOption' in opts === false ? false : opts['ifNoMatchThenAddOption'];
    const addOptionTxt = 'addOptionTxt' in opts === false ? "追加して選択する" : opts['addOptionTxt'];
    const maxHeight = 'maxHeight' in opts === false ? '30vh' : opts['maxHeight'];
    const maxImageSize = 'maxImageSize' in opts === false ? '30px' : opts['maxImageSize'];

    /**
     * 仮想テンプレート
     */
    const vHtml = "<div class=\"vSelectWrap\">" + 
                  " <div class=\"vDummySelect\"><input type=\"text\" readonly></div>" +
                  " <div class=\"vPopup\">" +
                  "  <div class=\"vSearch\"><input type=\"text\" placeholder=\"検索\"></div>" +
                  ( ifNoMatchThenAddOption ? 
                  "  <div class=\"vNoMatch hidden\">" +
                  "   <div class=\"vHeadline\">" + addOptionTxt + "</div>" +
                  "   <div class=\"vPlus\"></div>" +
                  "  </div><!-- div.vNoMatch -->"
                  : "" ) +
                  "  <div class=\"vResult\">" +
                  "   <div class=\"vHeadline\">検索結果</div>" +
                  "   <ul class=\"vSelect\"></ul>" +
                  "   <div class=\"noMatchText\">" + noMatchText + "</div>" +
                  "  </div><!-- div.vResult -->" +
                  " </div><!-- END div.vPopup -->" +
                  "</div><!-- END div.vSelectWrap -->";

    /**
     * ひとつずつ処理
     */
    $(this).each( (thisIdx, thisElem) => {
      // Uuidを取得
      $(thisElem).attr('data-uuid', getUuid());
      // 仮想エレメント
      let vElement = $(vHtml);
      // 基準値をコピー
      vElement.css({
        'display': $(thisElem).css('display'),
        'margin': $(thisElem).css('margin'),
        'width': $(thisElem).css('width'),
        'font-size': $(thisElem).css('font-size')
      });
      // ダミーデザインのコピー
      vElement.children('div.vDummySelect').children('input').css({
        'border': $(thisElem).css('border'),
        'font-size': $(thisElem).css('font-size'),
        'outline': $(thisElem).css('outline')
      });

      // 検索フォーム
      vElement.children('div.vPopup').children('div.vSearch').children('input').css({
        'font-size': $(thisElem).css('font-size')
      })
      .change(filterList(vElement, thisIdx))
      .keyup(filterList(vElement, thisIdx))
      ;

      // 選択して追加する
      vElement.children('div.vPopup').children('div.vNoMatch').children('div.vPlus').click(function() {
        let addLi = $('<li>').attr({
          'data-value': $(this).text()
        }).text( $(this).text() ).click(function() {
          setActiveSelect( $(this).closest('div.vSelectWrap'), $(this).text(), $(this).text() );
          closeActiveSelect();
        });
        $(this).closest('div.vPopup').children('div.vResult').children('ul.vSelect').append( addLi );
        setActiveSelect( $(this).closest('div.vSelectWrap'), $(this).text(), $(this).text() );
        closeActiveSelect();
      });

      // 検索結果
      let vProxySelect = vElement.children('div.vPopup').children('div.vResult').children('ul.vSelect').css({
        'max-height': maxHeight,
        'font-size': $(thisElem).css('font-size')
      });
      // デフォルト値
      let defOptionIdx = null;
      // optionを追加
      $('option', thisElem).each(function(optIdx) {
        let elemLi = $('<li>').attr('data-value', $(this).val()).text($(this).text());
        // サムネイルを表示
        if ($(this).attr('data-image')) {
          let elemImg = $('<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDkuMS1jMDAxIDc5LmE4ZDQ3NTM0OSwgMjAyMy8wMy8yMy0xMzowNTo0NSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDI0LjcgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjU5OTlFOEZBNDg2QzExRUU5NjY2RUZCMjkxMDAxMUY1IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjU5OTlFOEZCNDg2QzExRUU5NjY2RUZCMjkxMDAxMUY1Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NTk5OUU4Rjg0ODZDMTFFRTk2NjZFRkIyOTEwMDExRjUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NTk5OUU4Rjk0ODZDMTFFRTk2NjZFRkIyOTEwMDExRjUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz78X++XAAAAEElEQVR42mL4//8/A0CAAQAI/AL+26JNFgAAAABJRU5ErkJggg==' + '">').attr({
            'data-image': $(this).attr('data-image')
          }).css({
            'max-width': maxImageSize,
            'max-height': maxImageSize
          }).addClass('thumb');
          elemLi.prepend(elemImg);
          setTimeout( () => {
            elemImg.attr('src', elemImg.attr('data-image') );
          }, 1000);
        };
        // デフォルト値と一致
        if ($(thisElem).val() == $(this).val()) defOptionIdx = optIdx;
        // optionをクリック
        $(elemLi).click(function() {
          let optionValue = $(this).attr('data-value')[0] ? $(this).attr('data-value') : ($(this).val()[0] ? $(this).val() : $(this).text());
          setActiveSelect( $(this).closest('div.vSelectWrap'), $(this).text(), optionValue );
          closeActiveSelect();
        });
        vProxySelect.append(elemLi);
      });
      vElement.children('div.vPopup').children('div.vResult').children('div.noMatchText').addClass('hidden');

      // デフォルト値の設定
      if (defOptionIdx !== null) vProxySelect.children('li:eq(' + defOptionIdx + ')').trigger('click');

      // 代入してセレクトボックスを非表示
      $(thisElem).after(vElement).css('display', 'none');
    });

  };


  /**
   * イベント
   */
  $(document).on('mouseup', function(e) {
    if ($(e.target).closest('div.vSelectWrap')[0]) {
      let thisUuid = $(e.target).closest('div.vSelectWrap').prev().attr('data-uuid');
      /**
       * ポップアップ内をクリック
       */
      if ($(e.target).closest('div.vPopup')[0]) {
        e.stopPropagation();
        return;
      };

      /**
       * 仮想プルダウンをクリック
       */
      if ($(e.target).closest('div.vDummySelect')[0]) {
        e.stopPropagation();
        if (vSelectObj['activeSelect']) {
          let lastUuid = $(vSelectObj['activeSelect']).attr('data-uuid');
          closeActiveSelect();
          if (lastUuid == thisUuid) return;
        };
        vSelectObj['activeSelect'] = $(e.target).closest('div.vSelectWrap').prev();
        let selectWrap = $(vSelectObj['activeSelect']).next().addClass('isFocus');
        selectWrap.children('div.vPopup').children('div.vSearch').children('input').val('').focus().trigger('change');
        selectWrap.children('div.vPopup').children('div.vResult').children('ul.vSelect').scrollTop(0).scrollLeft(0);
        return;
      };
    };

    /**
     * vSelectWrapを閉じる
     *    vSelectWrap外をクリック時
     */
    if (vSelectObj['activeSelect']) {
      e.stopPropagation();
      closeActiveSelect();
    };

  });


  /**
   * 関数：vSelectにセットする
   */
  function setActiveSelect( vSelectWrap, insText, insValue ) {
    $(vSelectWrap).prev().val(insValue).trigger('change');
    $(vSelectWrap).children('div.vDummySelect').children('input').val(insText);
  };


  /**
   * 関数：vSelectを閉じる
   */
  function closeActiveSelect() {
    if (!vSelectObj['activeSelect']) return;
    let vSelectWrap = $(vSelectObj['activeSelect']).next().removeClass('isFocus');
    let vPopup = vSelectWrap.children('div.vPopup');
    $(vPopup).children('div.vSearch').children('input').val('');
    $(vPopup).children('div.vNoMatch').addClass('hidden');
    $(vPopup).children('div.vResult').children('ul.vSelect').children('li').removeClass('hidden');
    vSelectObj['activeSelect'] = null;
  };


  /**
   * 関数：検索フォームの変更
   */
  function filterList(vElement, selectIdx) {
    return(function() {
      let vPopup = vElement.children('div.vPopup');
      if (window['asyncFilter']) clearTimeout(window['asyncFilter']);
      window['asyncFilter'] = setTimeout( () => {
        let searchTxt = vPopup.children('div.vSearch').children('input').val();
        // 未入力
        if (!searchTxt) {
          vPopup.children('div.vNoMatch').addClass('hidden');
          vPopup.children('div.vResult').children('ul.vSelect').children('li').removeClass('hidden');
          vPopup.children('div.vResult').children('div.noMatchText').addClass('hidden');
          return;
        };
        // 検索
        let isMatch = false;
        let hitCount = 0;
        vPopup.children('div.vResult').children('ul.vSelect').children('li').each(function(liIdx, liElem) {
          if (liElem.innerText.indexOf(searchTxt) !== -1) {
            if (liElem.innerText == searchTxt) isMatch = true;
            hitCount++;
            $(this).removeClass('hidden');
          } else {
            $(this).addClass('hidden');
          };
        });
        // 一致
        if (isMatch) vPopup.children('div.vNoMatch').addClass('hidden');
        else {
          vPopup.children('div.vNoMatch').removeClass('hidden');
          vPopup.children('div.vNoMatch').children('div.vPlus').text(searchTxt);
        };
        // ヒット
        if (hitCount > 0) vPopup.children('div.vResult').children('div.noMatchText').addClass('hidden');
        else vPopup.children('div.vResult').children('div.noMatchText').removeClass('hidden');
      }, 100);
    });
  };

  /**
   * 関数：UUIDの生成
   */
  function getUuid() {
    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);
    });
  };


})(jQuery);