import { Injectable } from '@angular/core';
import { parse } from './atlas.pegjs';

const beginObject = '(';
const endObject = ')';
const nameSeparator = '=';
const valueSeparator = ',';

@Injectable({
  providedIn: 'root'
})
export class PegjsService {

  constructor() {}

  public static parse(input: string): object {
    let output = {};
    try {
      output = parse(input);
    } catch (e) {
      // TODO put a popover somewhere with a location of the error
      console.log(e);
      console.log(e.location);
    }
    return output;
  }

  public static format(input: object, skipCurrentObject?: boolean): string {
    return PegjsService.deparseJson(input, undefined, skipCurrentObject)
  }

  private static deparseJson(input, key?, skip?: boolean) {
    // Call possible toJSON on object
    if(!skip && typeof input === 'object' && typeof input.toJSON === 'function') {
      input = input.toJSON();
    }
    switch (typeof input) {
      case "object":
        return PegjsService.deparseObject(input);
      case "number":
        return PegjsService.deparseNumber(input, key);
      case "string":
        return PegjsService.deparseString(input);
      case "undefined":
        return "";
      case "boolean":
        return PegjsService.deparseBoolean(input);
      default:
        console.log("Unknown type for input", input);
        return "";
    }
  }

  private static deparseObject(input) {
    if (Array.isArray(input)) {
      return this.deparseArray(input);
    }
    if (input === null) {
      return "None";
    }

    let output = '';
    output += beginObject;

    Object.keys(input).forEach(function (key, idx, array) {
      output += key;
      output += nameSeparator;
      output += PegjsService.deparseJson(input[key], key);

      if (idx !== array.length - 1) {
        // Not the last item
        output += valueSeparator
      }
    });
    output += endObject;

    return output;
  }

  private static deparseArray(input) {
    // We have one funky array option, where its 2 values and one of them is a recognised class.
    // These are here for easier maintenance, as adding any new ones should just work. These all
    // Work off string equality, see found below.
    const specialCases = [
      'BlueprintGeneratedClass',
      'Blueprint',
      'SoundWave',
      'Texture2D'
    ];

    const found = specialCases.indexOf(input[0]);
    if (found > -1) {
      // We found one of our special cases!
      const val = specialCases[found];
      return val + "'" + input[1] + "'";
    }

    let output = '';
    output += beginObject;

    input.forEach(function (data, idx, array) {
      output += PegjsService.deparseJson(data);

      if (idx !== array.length - 1) {
        output += valueSeparator;
      }
    });
    output += endObject;

    return output;
  }

  private static deparseNumber(input, key) {
    // Any number which has a decimal is stored to 6 decimal places
    // Except for IDs. Unless they actually have such a number... erm...
    if (key.substr(key.length - 2, 2) === "ID") {
      if (input % 1 === 0) {
        return Number(input).toString();
      }
      // Else drop out and return as normal
    }
    return Number(input).toFixed(6);
  }

  private static deparseString(input) {
    // We need to re-encode the strings properly
    return JSON.stringify(input);
  }

  private static deparseBoolean(input) {
    if ( input ) {
      return 'True';
    } else {
      return 'False';
    }
  }
}
