new Promise(()=>{
 "use strict";

window.nl_watch.nlMediaInfo = {
  intervalTime: 1000, //キャッシュ中更新間隔(ミリ秒)
  cachingItems: 60, //キャッシュ中,予想完了時間に使う個数
  //予想完了時間は[intervalTime]と[cachingItems]で算出、デフォルトは直近60秒の平均で算出
  
  smid: '',
  data: {},
  oldSize: {},
  Arr: {},
  cachingsId:[],
/*******************************************/
  init() {
    if(!document.getElementById('nl_itab_Header')) return requestAnimationFrame(this.init.bind(this));
    
    this.smid = window.nl_watch.apiData.video.id;
    this.data = {};
    this.oldSize = {};
    this.Arr = {};
    this.cachingsId = [];
    
    window.nl_watch.$XHR(`/cache/info/v2?${this.smid}`).then(this.CacheInfo.bind(this));
    const
      E = document.getElementById('MainVideoPlayer').firstElementChild
      ,F = () => {
        window.nl_watch.$XHR(`/cache/info/v2?${this.smid}`).then(this.CacheInfo.bind(this));
        E.removeEventListener("play", F, false);
      };
    E.addEventListener("play", F, false);
  },
/*******************************************/
  CacheInfo(aJson) {
    var
      json = JSON.parse(aJson.responseText)[this.smid]
      ,haveCachings = false
      ,haveCompletes = false;
    
    //console.log(`CacheInfo`);
    if(!json || !((haveCachings = json["cachings"].length) || (haveCompletes = json["completes"].length))) return;
    //console.log(`cachings: ${json["cachings"]}`);
    //console.log(`completes: ${json["completes"]}`);
    
    if (haveCachings) {
      for(let cacheId of json["cachings"]) {
        this.data[cacheId] = {};
        this.Arr[cacheId] = [];
        this.oldSize[cacheId] = 0;
      }
      this.CachingsInfo(json);
    }
    if (haveCompletes) {
      json["completes"].forEach(cacheId => this.data[cacheId] = {})
      this.CompletesInfo(json);
    }
  },
/*******************************************/
  CachingsInfo(aJson) {
    const
      cachings = aJson["cachings"]
      ,completes = aJson["completes"];
    
    if (cachings.length) {
      Promise
        .all([for(c of cachings) new Promise(r => r(aJson.caches[c])).then(this.CacheInfo2.bind(this))])
        .then(() => cachings.forEach(aValue => Promise.resolve(this.cachingWrite(aValue))));
      window.setTimeout(() => window.nl_watch.$XHR(`/cache/info/v2?${this.smid}`).then((r) => this.CachingsInfo.call(this, JSON.parse(r.responseText)[this.smid])), this.intervalTime);
    }
    
    if (this.cachingsId.length > cachings.length) {
      for (let i of this.cachingsId) {
        if (!cachings.includes(i)) {
          //console.log(`CItrue_${i}`);
          let
            id = i.match(/([^\]]+\])[^.]+(\..+)/)
            ,completeId = i
            ,Arr = []
            ,applyArr = [i];
          
          if (id && completes.includes(`${id[1]}${id[2]}`)) {
            completeId = `${id[1]}${id[2]}`;
            this.data[completeId] = {};
            Arr.push(new Promise(r => r(aJson.caches[completeId])).then(this.CacheInfo2.bind(this)));
            applyArr = [completeId, i];
          }
          if (!this.data.TI_video_id) Arr.push(Promise.resolve(this.GetThumbinfo(this.smid)));
          Arr.push(window.nl_watch.$XHR(`/cache/mediainfo?${completeId}`, completeId).then(this.GetMediainfo.bind(this)));
          
          Promise
            .all(Arr)
            .then(() => Promise.resolve(this.Write.apply(this, applyArr)));
        }
      }
    }
    this.cachingsId = cachings;
  },
/*******************************************/
  cachingWrite(aCacheId) {
    //console.log(`ingW_${aCacheId}`);
    const
      DATA = this.data
      ,CacheDATA = this.data[aCacheId]
      ,cachingSize = CacheDATA["cachingSize"]
      ,size = CacheDATA["size"]
      ,oldSize = this.oldSize[aCacheId]
      ,Arr = this.Arr[aCacheId]
      ,TIME = () => {
       if (!this.Arr[aCacheId].length) return '';
       const _TIME = ((size -cachingSize) /(this.ave(this.Arr[aCacheId]) /(this.intervalTime /1000))) |0
       if (_TIME > 60) {
         return ` 予想完了時間${(_TIME /60) |0}分${_TIME %60}秒`;
       } else {
         return ` 予想完了時間${_TIME}秒`;
       }
      }
      ,cachingText1 = `${(cachingSize *100 /size)|0}%`
      ,cachingText2 = `[${((cachingSize -oldSize) /1024)|0} Kbps] ${this.str(cachingSize,'K')} / ${this.str(size,'K')}`
      ,cachingText3 = `キャッシュ中です... ${cachingText1} (${cachingText2} ダウンロード${TIME()})`;
    
    if (!document.getElementsByClassName(`nl_itab_Headers ${aCacheId}`).item(0)) {
      document.getElementById('nl_itab_Header')
        .insertAdjacentHTML("BeforeEnd", `<a href="javascript:void(0)" onClick="nl_watch.nl_itab(this, '${aCacheId}');" class="nl_itab_Headers ${aCacheId}">${aCacheId} (${cachingText1} ${cachingText2})</a>`);
      document.getElementById('nl_itab_Frame')
        .insertAdjacentHTML("BeforeEnd", `<div class="mediainfo nl_itab_Bodies ${aCacheId}"><div class="MIcachingInfo">${cachingText3}</div></div>`);
    } else {
      document.getElementsByClassName(`nl_itab_Headers ${aCacheId}`)[0].textContent = `${aCacheId} (${cachingText1} ${cachingText2})`;
      document.getElementsByClassName(`nl_itab_Bodies ${aCacheId}`)[0].firstElementChild.textContent = `${cachingText3}`;
    }
    
    if (oldSize) {
      Arr.unshift(cachingSize -oldSize);
      this.Arr[aCacheId] = Arr.slice(0, this.cachingItems);
    }
    this.oldSize[aCacheId] = cachingSize;
  },
/*******************************************/
  CompletesInfo(aJson) {
    const
      completes = aJson["completes"]
      ,A1 = [for(c of completes) new Promise(r => r(aJson.caches[c])).then(this.CacheInfo2.bind(this))]
      ,A2 = [for(c of completes) window.nl_watch.$XHR(`/cache/mediainfo?${c}`, c).then(this.GetMediainfo.bind(this))]
      ,Arr = [Promise.resolve(this.GetThumbinfo(this.smid)), ...A1, ...A2];
      
    Promise
      .all(Arr)
      .then(() => completes.forEach(aValue => Promise.resolve(this.Write(aValue))));
  },
/*******************************************/
  CacheInfo2(aJson) {
    const
      {
        videoId,
        cacheId,
        complete,
        economy,
        dmc,
        dmcMovieType,
        caching,
        movieType,
        size,
        cachingSize,
        title,
        subFolder,
        filename,
        ts,
        reEncoded,
      } = aJson
      ,DATA = this.data[cacheId];
    
    //console.log(`CI2_${cacheId}`);
    DATA.cacheType  = economy? '[low]': '';
    DATA.cacheTitle = title;
    DATA.subFolder  = subFolder? subFolder: '';
    DATA.ts         = ts? this.dateChange(ts): '';
    DATA.reEncoded  = reEncoded;
    DATA.caching    = caching;
    DATA.cachingSize= cachingSize;
    DATA.size       = size;
    
    if (dmc) {
      DATA.dmc             = dmc;
      DATA.dmcVideoMode    = dmcMovieType["videoMode"];
      DATA.dmcVideoBitrate = dmcMovieType["videoBitrate"];
      DATA.dmcAudioBitrate = dmcMovieType["audioBitrate"];
    }
  },
/*******************************************/
  GetThumbinfo(aSmid) {
    //console.log(`GTi_${aSmid}`);
    const
      DATA = this.data
      ,isDeleted = window.nl_watch.apiData.video.isDeleted
      ,$F = xml => {
        xml = new DOMParser().parseFromString(xml, 'application/xml');
        
        const
          DATA = window.nl_watch.nlMediaInfo.data
          ,selector = ['video_id', 'movie_type', 'length'];
        selector.forEach(S => DATA[`TI_${S}`] = xml.getElementsByTagName(S)[0].textContent);
        
        const
          size_high = xml.getElementsByTagName('size_high')[0].textContent -0
          ,size_low = xml.getElementsByTagName('size_low')[0].textContent -0;
        DATA.TI_size_high = size_high > 0? this.str(size_high,'M'): 'None';
        DATA.TI_size_low  = size_low  > 0? this.str(size_low ,'M'): 'None';
      };
    var  d;
    
    if (isDeleted) {
      DATA.TI_video_id   = 'None';
      DATA.TI_movie_type = 'None';
      DATA.TI_length     = 'None';
      DATA.TI_size_high  = 'None';
      DATA.TI_size_low   = 'None';
    } else if ((d = window.popThumb.data[`obj_${aSmid}`]) && (d = d[1]).usingAPI.getthumbinfo) {
      DATA.TI_video_id   = d.video_id;
      DATA.TI_movie_type = d.movie_type;
      DATA.TI_length     = d.length;
      DATA.TI_size_high  = d.size_high > 0? this.str(d.size_high,'M'): 'None';
      DATA.TI_size_low   = d.size_low  > 0? this.str(d.size_low ,'M'): 'None';
    } else {
      window.popThumb.HttpRequest(`/pr_Redirect_ext.nicovideo.jp/api/getthumbinfo/${aSmid}`, $F, true, aSmid, ['api', aSmid]);
    }
  },
/*******************************************/
  GetMediainfo([aXml, aCacheId]) {
    //console.log(`GMi_${aCacheId}`);
    const 
      xml = new DOMParser().parseFromString(aXml.responseText, 'application/xml')
      ,SELECTOR = {
        General:['Format', 'Format_profile', 'Overall_bit_rate', 'File_size'],
        Video:['Format', 'Format_profile', 'Bit_rate_mode', 'Bit_rate', 'Frame_rate', 'Stream_size'],
        Audio:['Format', 'Format_profile', 'Bit_rate_mode', 'Bit_rate', 'Channel_s_', 'Sampling_rate', 'Stream_size'],
      }
      ,DATA = this.data[aCacheId];
    var s;
    for (let x in SELECTOR) {
      for (let S of SELECTOR[x]) {
        if (!(s = this.qSele(xml, x, S))) {
          DATA[`MI_${x}_${S}`] = '';
          continue;
        }
        switch (S) {
          case 'File_size':
            s = s.textContent.replace(/(\.\d)\d/g, '$1');
            break;
          case 'Overall_bit_rate':
            s = s.textContent.replace(/ (?=\d)/g, ',');
            break;
          case 'Bit_rate_mode':
            s = '(' + s.textContent + ')';
            break;
          case 'Bit_rate':
            s = s.textContent.replace(/ (?!K)/g, ',').replace(/\.\d/g, '');
            break;
          case 'Stream_size':
            let R = s.textContent.replace(/(\.\d)\d/g, '$1').match(/^(.+B) (.+)$/);
            s=R[1];
            DATA[`MI_${x}_${S}_percent`] = R[2];
            break;
          default:
            s = s.textContent;
            break;
        }
        DATA[`MI_${x}_${S}`] = s;
      }
    }
    
    var
      MI_Video_Width = this.qSele(xml, 'Video', 'Width')
      ,MI_Video_Height = this.qSele(xml, 'Video', 'Height');
    if (MI_Video_Width && MI_Video_Height) {
      let
        width = MI_Video_Width.textContent.slice(0, -7).replace(' ', ',')
        ,height = MI_Video_Height.textContent.slice(0, -7).replace(' ', ',');
      DATA.MI_Resolution = (`${width} x ${height}`);
    }
  },
/*******************************************/
  Write(aCacheId ,aCacheId2) {
    //console.log(`W_${aCacheId}`);
    const
      DATA = this.data
      ,CacheDATA = this.data[aCacheId];
    
    const element = (
      '<div id="MediainfoTable">'+
//------------------------------------------------
        '<div class="mi_TitleT">タイトル</div>'+
        '<div class="mi_MIsep1-1">:</div>'+
        `<div class="mi_Title"><span id="cacheType">${CacheDATA.cacheType}</span> <span id="cacheTitle">${CacheDATA.cacheTitle}</span></div>`+
//------------------------------------------------
        '<div class="mi_InfoT">動画情報</div>'+
        '<div class="mi_MIsep2-1">:</div>'+
        `<div class="mi_vId"><span id="TI_video_id">${DATA.TI_video_id}</span></div>`+
        '<div class="mi_MIsep2-2">/</div>'+
        `<div class="mi_mType"><span id="TI_movie_type">` + (CacheDATA.dmc? `[${CacheDATA.dmcVideoMode},${CacheDATA.dmcVideoBitrate},${CacheDATA.dmcAudioBitrate}].`: '') + `${DATA.TI_movie_type}</span></div>`+
        '<div class="mi_MIsep2-3">/</div>'+
        `<div class="mi_sizeH"><span id="TI_size_high">${DATA.TI_size_high}</span></div>`+
        '<div class="mi_MIsep2-4">/</div>'+
        `<div class="mi_sizeL">Economy:<span id="TI_size_low">${DATA.TI_size_low}</span></div>`+
//------------------------------------------------
        '<div class="mi_FormatT">形式</div>'+
        '<div class="mi_MIsep3-1">:</div>'+
        `<div class="mi_Format"><span id="MI_General_Format">${CacheDATA.MI_General_Format}</span><span id="MI_General_Format_profile">${CacheDATA.MI_General_Format_profile}</span></div>`+
        '<div class="mi_MIsep3-2">/</div>'+
        `<div class="mi_bitRate"><span id="MI_General_Overall_bit_rate">${CacheDATA.MI_General_Overall_bit_rate}</span></div>`+
        '<div class="mi_MIsep3-3">/</div>'+
        `<div class="mi_fileSize"><span id="MI_General_File_size">${CacheDATA.MI_General_File_size}</span></div>`+
        '<div class="mi_MIsep3-4">/</div>'+
        `<div class="mi_Length"><span id="TI_length">${DATA.TI_length}</span></div>`+
//------------------------------------------------
        '<div class="mi_VideoT">映像</div>'+
        '<div class="mi_MIsep4-1">:</div>'+
        `<div class="mi_vFormat"><span id="MI_Video_Format">${CacheDATA.MI_Video_Format}</span> <span id="MI_Video_Format_profile">${CacheDATA.MI_Video_Format_profile}</span></div>`+
        '<div class="mi_MIsep4-2">/</div>'+
        '<div class="mi_vBitRateC">'+
          `<span class="mi_vBitRate"><span id="MI_Video_Bit_rate">${CacheDATA.MI_Video_Bit_rate}</span></span>`+
          `<span class="mi_vBitRateM zw_paddingL"><span id="MI_Video_Bit_rate_mode">${CacheDATA.MI_Video_Bit_rate_mode}</span></span>`+
        '</div>'+
        '<div class="mi_MIsep4-3">/</div>'+
        '<div class="mi_vStreamSizeC">'+
          `<span class="mi_vStreamSize"><span id="MI_Video_Stream_size">${CacheDATA.MI_Video_Stream_size}</span></span>`+
          `<span class="mi_vStreamSizeP zw_paddingL"><span id="MI_Video_Stream_size_percent">${CacheDATA.MI_Video_Stream_size_percent}</span></span>`+
        '</div>'+
        '<div class="mi_MIsep4-4">/</div>'+
        `<div class="mi_Resolution"><span id="MI_Resolution">${CacheDATA.MI_Resolution}</span> <span id="MI_Video_Frame_rate" style="white-space:nowrap;">@ ${CacheDATA.MI_Video_Frame_rate}</span></div>`+
//------------------------------------------------
        '<div class="mi_AudioT">音声</div>'+
        '<div class="mi_MIsep5-1">:</div>'+
        `<div class="mi_aFormat"><span id="MI_Audio_Format">${CacheDATA.MI_Audio_Format}</span> <span id="MI_Audio_Format_profile">${CacheDATA.MI_Audio_Format_profile}</span></div>`+
        '<div class="mi_MIsep5-2">/</div>'+
        '<div class="mi_aBitRateC">'+
          `<span class="mi_aBitRate"><span id="MI_Audio_Bit_rate">${CacheDATA.MI_Audio_Bit_rate}</span></span>`+
          `<span class="mi_aBitRateM zw_paddingL"><span id="MI_Audio_Bit_rate_mode">${CacheDATA.MI_Audio_Bit_rate_mode}</span></span>`+
        '</div>'+
        '<div class="mi_MIsep5-3">/</div>'+
        '<div class="mi_aStreamSizeC">'+
          `<span class="mi_aStreamSize"><span id="MI_Audio_Stream_size">${CacheDATA.MI_Audio_Stream_size}</span></span>`+
          `<span class="mi_aStreamSizeP zw_paddingL"><span id="MI_Audio_Stream_size_percent">${CacheDATA.MI_Audio_Stream_size_percent}</span></span>`+
        '</div>'+
        '<div class="mi_MIsep5-4">/</div>'+
        `<div class="mi_aSamplingRate"><span id="MI_Audio_Sampling_rate">${CacheDATA.MI_Audio_Sampling_rate}</span> <span id="MI_Audio_Channel_s_" style="white-space:nowrap;">@ ${CacheDATA.MI_Audio_Channel_s_}</span></div>`+
//------------------------------------------------
        '<div class="mi_TimestampT">ﾀｲﾑｽﾀﾝﾌﾟ</div>'+
        '<div class="mi_MIsep6-1">:</div>'+
        `<div class="mi_ts"><span id="MI_ts">${CacheDATA.ts}</span></div>`+
        (CacheDATA.reEncoded !== undefined?
          '<div class="mi_MIsep6-2">|</div>'+
          '<div class="mi_reEncodedT">reEncoded</div>'+
          '<div class="mi_MIsep6-3">:</div>'+
          `<div class="mi_reE"><span id="MI_reE">${CacheDATA.reEncoded}</span></div>`
          : '<div class="mi_MIspace6-2"></div>'
        )+
//------------------------------------------------
        `<div class="mi_FolderT">フォルダ</div>`+
        '<div class="mi_MIsep7-1">:</div>'+
        `<div class="mi_Folder"><span id="MI_subFolder">${CacheDATA.subFolder}</span></div>`+
    '</div>');

    if (!document.getElementsByClassName(`nl_itab_Headers ${aCacheId2? aCacheId2: aCacheId}`).item(0)) {
      document.getElementById('nl_itab_Header')
        .insertAdjacentHTML("BeforeEnd", `<a href="javascript:void(0)" onClick="nl_watch.nl_itab(this, '${aCacheId}');" class="nl_itab_Headers ${aCacheId}">${aCacheId}</a>`);
      document.getElementById('nl_itab_Frame')
        .insertAdjacentHTML("BeforeEnd", `<div class="mediainfo nl_itab_Bodies ${aCacheId}">${element}</div>`);
    } else {
      document.getElementsByClassName(`nl_itab_Headers ${aCacheId2? aCacheId2: aCacheId}`)[0].innerHTML = `${aCacheId}`;
      document.getElementsByClassName(`nl_itab_Bodies ${aCacheId2? aCacheId2: aCacheId}`)[0].innerHTML = `${element}`;
    }
  },
/*******************************************/
  ave(aArray) {
    const SUM = aArray.reduce((previousValue, currentValue, index, array) => previousValue + currentValue);
    return (SUM /aArray.length) |0;
  },

  qSele(aXml, aType, aTag) {
    return aXml.querySelector(`track[type="${aType}"] > ${aTag}`);
  },

  str(V, aUnit) {
    var U = (aUnit === 'K')? 1024:
            (aUnit === 'M')? (1024 *1024): 1;
    V = ((V /U).toLocaleString()) +'';
    U = V.indexOf('.');
    return `${!~U? V: V.slice(0, U)} ${aUnit}iB`;
  },

  dateChange(aDate) {
    const
      dates = ((new Date(aDate *1000)).toISOString()).split('T')
      ,[year, month, date] = dates[0].split('-')
      ,[hour, minute, second] = (dates[1].split('.'))[0].split(':');
    return `${year}年${month}月${date}日${hour}時${minute}分${second}秒`;
  },
};

//window.nl_watch.nlMediaInfo.init.call(window.nl_watch.nlMediaInfo);
window.nl_watch.eventListenerMap.add(window.nl_watch.nlMediaInfo.init.bind(window.nl_watch.nlMediaInfo));
});