"use strict";

const fs = require('fs');
const path = require('path');
const utils = require('../util/utils');
const Loader = require('pomelo-loader');
const pathUtil = require('../util/pathUtil');
const crypto = require('crypto');

module.exports = function(app, opts) {
  return new ComponentDictionary(app, opts);
};

/** Dictionary Component Class
 * 
 * @class
 * @implements {Component}
 * 
 * @param {import('./server').Application} app  current application context
 * @param {Object} opts construct parameters
 */
class ComponentDictionary
{
  constructor(app, opts) {
    this.name = '__dictionary__';

    this.app = app;
    this.dict = {};
    this.abbrs = {};
    this.userDicPath = null;
    this.version = "";
  
    /**
     * @type {Object.< string, string[]>}
     */
    this.cusRouteMap = {
  
    };
  
  
    //Set user dictionary
    let p = path.join(app.getCfgPath('dictionary.json'));
    if(!!opts) {
      // user dict
      if( !!opts.dict ) {
        p = opts.dict;
      }
    }
   
    if(fs.existsSync(p)) {
      this.userDicPath = p;
    }
  }


  start(cb) {

    let userDict = {
      route: {},
      notify:[]
    };

    try{
      let szUserDict = fs.readFileSync( this.userDicPath );
      let userDictT = JSON.parse( szUserDict );
      let typeRoute = typeof(userDictT.route);
      let typeNotify = typeof(userDictT.notify);

      if( (typeRoute !== 'undefined') && (typeRoute !== 'object') ) {
        throw Error('error route format');
      }

      if( (typeNotify !== 'undefined') && (typeRoute !== 'object') && ((typeNotify instanceof Array) === false) ) {
        throw Error('error notify format');
      }

      userDict = userDictT;
    }catch(err) {
      console.warn('--- dictionary err', err);
    }

    let cntTypes = 0;
    if( userDict.route !== undefined ) {
      for( let serType in userDict.route ) {
        // check server type group
        let serTypeT = this.app.get(serType);
        if( serTypeT ) {
          this.cusRouteMap[serTypeT] = userDict.route[serType];
          cntTypes++;
        } else {
          this.cusRouteMap[serType] = userDict.route[serType];
          cntTypes++;
        }
      }
    }


    let servers = this.app.get('servers');
    let routes = [];
  
    if( cntTypes > 0) {
      for(let serverType in servers) {
        let cusRoute = this.getCustomRoute(serverType);
        if( cusRoute.length > 0 ) {
          for( let it of cusRoute ) {
            routes.push(`${serverType}.${it}`);
          }
        }
      }
    }
  
    //Sort the route to make sure all the routers abbr are the same in all the servers
    routes.sort();
    let abbr;
    let i;
    for(i = 0; i < routes.length; i++) {
      abbr = i + 1;
      this.abbrs[abbr] = routes[i];
      this.dict[routes[i]] = abbr;
    }
  
    //Load user dictionary
    if(userDict.notify !== undefined) {
      abbr = routes.length + 1;
      for(i = 0; i < userDict.notify.length; i++) {
        let route = userDict.notify[i];
  
        this.abbrs[abbr] = route;
        this.dict[route] = abbr;
        abbr++;
      }
    }
  
    this.version = crypto.createHash('md5').update(JSON.stringify(this.dict)).digest('base64');
  
    utils.invokeCallback(cb);
  }


  getDict() {
    return this.dict;
  }
  
  getRouteNum(route) {
    return this.dict[route];
  }
  
  getAbbrs() {
    return this.abbrs;
  }
  
  getAbbr(routeNum) {
    return this.abbrs[routeNum];
  }
  
  getVersion() {
    return this.version;
  }
  
  getCustomRoute (serType) {
    for( let it in this.cusRouteMap ) {
      if( contains( serType, it ) === true ){
        return this.cusRouteMap[it];
      }
    }
    return [];
  }
}


let contains = function(str, settings) {
  if(!settings) {
      return false;
  }

  let exclude = ( settings.charAt(0) === '!' );
  let ts = settings.split("|");
  if( exclude ){
      ts[0] = ts[0].substr(1);
  }

  return exclude?(ts.indexOf(str) === -1) : (ts.indexOf(str) !== -1);
};