export enum CharactorType {
  Number = 'Number',
  Charactor = 'Charactor',
  Space = 'Space',
  Special = 'Special'
}

const CharCodeZero = '0'.charCodeAt(0);
const CharCodeNine = '9'.charCodeAt(0);

export class StringUtil {
  /**
   * prefix zero fill
   * @param str target string
   * @param len fill in length
   */
  public static zeroFill(str: any, len: number): string {
    if (typeof str === 'string') {
      let fillin = '';
      for (let i = 0; i < len - str.length; i++) {
        fillin += '0';
      }
      return fillin + str;
    } else if (typeof str === 'number') {
      return StringUtil.zeroFill(str.toString(), len);
    }
  }

  /**
   * includes
   */
  public static includes(target: string, charactorType: CharactorType): number {
    let nNum = 0;
    let nChar = 0;
    let nSpace = 0;
    let nElse = 0;

    for (let i = 0; i < target.length; i++) {
      const char = target.charCodeAt(i);
      // 숫자
      if (char >= 48 && char <= 57) {
        nNum++;
      } else if (char >= 65 && char <= 90) {
        // 영어(대문자)
        nChar++;
      } else if (char >= 97 && char <= 122) {
        // 영어(소문자)
        nChar++;
      } else if (target.charAt(i) === ' ') {
        // 공백
        nSpace++;
      } else {
        // 특수기호
        nElse++;
      }
    }

    switch (charactorType) {
      case CharactorType.Number:
        return nNum;
      case CharactorType.Charactor:
        return nChar;
      case CharactorType.Space:
        return nSpace;
      case CharactorType.Special:
        return nElse;

      default:
        return -1;
    }
  }

  /**
   * isRepeat
   */
  public static isRepeat(target: string, repeatTime: number) {
    let old = '';
    let rptCnt = 1;
    for (let i = 0; i < target.length; i++) {
      const s = target.charAt(i);
      if (old === s) {
        rptCnt++;
        if (rptCnt === repeatTime) {
          return true;
        }
      } else {
        old = s;
        rptCnt = 1;
      }
    }
    return false;
  }

  /**
   * isIncrements
   */
  public static isIncrements(target: string, repeatTime: number) {
    for (let i = 0; i < target.length - (repeatTime - 1); i++) {
      let notNeed = false;
      const ary: number[] = [];
      for (let j = 0; j < repeatTime; j++) {
        const char = target.charCodeAt(i + j);
        if (!StringUtil.isAlphaNumeric(char)) {
          notNeed = true;
          break;
        }
        ary.push(char);
      }

      if (notNeed) {
        continue;
      }

      for (let k = 1; k < ary.length; k++) {
        if (ary[0] !== ary[k] - k) {
          notNeed = true;
          break;
        }
      }

      if (notNeed) {
        continue;
      }

      return true;
    }
    return false;
  }

  /**
   * isIncrements
   */
  public static isDecrements(target: string, repeatTime: number) {
    for (let i = 0; i < target.length - (repeatTime - 1); i++) {
      let notNeed = false;
      const ary: number[] = [];
      for (let j = 0; j < repeatTime; j++) {
        const char = target.charCodeAt(i + j);
        if (!StringUtil.isAlphaNumeric(char)) {
          notNeed = true;
          break;
        }
        ary.push(char);
      }

      if (notNeed) {
        continue;
      }

      for (let k = 1; k < ary.length; k++) {
        if (ary[0] !== ary[k] + k) {
          notNeed = true;
          break;
        }
      }

      if (notNeed) {
        continue;
      }

      return true;
    }
    return false;
  }

  /**
   * isAlphabet
   */
  public static isAlphabet(char: number): boolean {
    return (char >= 65 && char <= 90) || (char >= 97 && char <= 122);
  }
  /**
   * isNumeric
   */
  public static isNumeric(char: number): boolean {
    return char >= 48 && char <= 57;
  }
  /**
   * isAlphaNumeric
   */
  public static isAlphaNumeric(char: number): boolean {
    return StringUtil.isAlphabet(char) || StringUtil.isNumeric(char);
  }
}
