const util = require('util');
let fs = require("fs");
let path = require('path');

export default class Utils {

/**
 * Extends the target by the most inner props of sources
 * @param {Object} target
 * @returns {Object}
 */
public static deepExtend(target: any, ...args:Array<any>) {
  const sources = Array.prototype.slice.call(arguments, 1);
  sources.forEach(function (source: any) {
    for (const prop in source) {
      if (!source.hasOwnProperty(prop)) {
        continue;
      }
      const targetProp = target[prop];
      const targetType = (typeof targetProp);
      //target prop is
      // a native single type
      // or not existent
      // or is not an anonymous object (not class instance)
      if (!targetProp ||
        targetType === 'number' ||
        targetType === 'string' ||
        util.isArray(targetProp) ||
        util.isDate(targetProp) ||
        targetProp.constructor.name !== 'Object') {
        target[prop] = source[prop];
      }
      else {
        //inner extend
        target[prop] = Utils.deepExtend({}, targetProp, source[prop]);
      }
    }
  });
  return target;
}

/**
* add 0 in front of single digit numbers
* @param {*} num 
*/
public static pad(num: number) {
  return (num > 9 ? "" : "0") + num;
}

/**
* attempt to convert ipv6 to ipv4(it will remain ipv6 if it can't be done)
*/
public static getIp(req: any) {
  if(req == null) return undefined;  

  let ip = req.ip ||
    req._remoteAddress ||
    (req.connection && req.connection.remoteAddress) ||
    undefined;

  /**
   * workaround because express uses ipv6 by default
   * The alternative is to listen on 0.0.0.0 : exp: server.listen(port, '0.0.0.0');
   */
  if (ip != undefined) {

    //ipv6 to ipv4 conversion if possible
    if (ip.substr(0, 7) == "::ffff:") {
      ip = ip.substr(7);
    }

    //localhost ipv6 to ipv4
    if (ip == "::1") {
      ip = "127.0.0.1";
    }
  };

  //this will be an ipv4 if possible with default to an ipv6 if not
  return ip;
}

public static readFromFile(filename: string): Object | null {
  if(typeof filename != "string") return null;
  
  let buf = fs.readFileSync(filename, "utf8");
  if(buf == null) return null;

  let options = JSON.parse(buf);

  if(typeof options == "object"){
      return options;
  }else{
      return null;
  }
}

public static getFullRouteFrom(filename?: string | null){
  var appDir = __dirname;
  if(require.main){
    appDir = path.dirname(require.main.filename);
  }
  if(filename == null) return appDir;
  return appDir + "/" + filename;
}

public static convertToBytesSize(size: number): string{
  Number.MAX_VALUE
  if(size <= 0) return size.toString();

  let unit = "B"
  let order = Math.floor(Math.log2(size) / 10);

  if(order >= 6) return "+1023.99PB";
  let divider = Math.pow(1024, order);

  switch(order){
      case 1: unit = "KB"; break;
      case 2: unit = "MB"; break;
      case 3: unit = "GB"; break;
      case 4: unit = "TB"; break;
      case 5: unit = "PB"; break;
  }
  return (size / divider).toFixed(2) + unit;
}
}