import { AfterViewInit, Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';

@Component({
  moduleId: module.id,
  selector: 'playground',
  templateUrl: 'playground.component.html',
  styleUrls: [ 'playground.component.css' ]
})
export class PlaygroundComponent implements OnInit, AfterViewInit {
  private examples: any = {
    exampleSetList: [ 'asf', 'rjsf', 'jsf', 'ng2jsf' ],
    exampleSets: {
      'asf': 'Angular Schema Form compatibility examples',
      'rjsf': 'React JSON Schema Form compatibility examples',
      'jsf': 'JSONForm compatibility examples',
      'ng2jsf': 'Other examples',
    },
    exampleList: {
      'asf': [
        'asf-simple', 'asf-basic-json-schema-type', 'asf-bootstrap-grid',
        'asf-complex-key-support', 'asf-array', 'asf-tab-array',
        'asf-titlemap-examples', 'asf-kitchen-sink', 'asf-hack-conditional-required',
      ],
      'rjsf': [
        'rjsf-simple', 'rjsf-nested', 'rjsf-arrays', 'rjsf-numbers', 'rjsf-widgets',
        'rjsf-ordering', 'rjsf-references', 'rjsf-errors', 'rjsf-large',
        'rjsf-date-and-time', 'rjsf-validation', 'rjsf-files', 'rjsf-custom',
      ],
      'jsf': [
        'jsf-gettingstarted',
        'jsf-schema-basic', 'jsf-schema-morecomplex', 'jsf-schema-array',
        'jsf-schema-required', 'jsf-schema-default', 'jsf-schema-inlineref',
        'jsf-fields-common', 'jsf-fields-password', 'jsf-fields-textarea',
        'jsf-fields-autocomplete', 'jsf-fields-ace', 'jsf-fields-color',
        'jsf-fields-checkbox', 'jsf-fields-checkboxes', 'jsf-fields-select',
        'jsf-fields-radios', 'jsf-fields-radiobuttons', 'jsf-fields-checkboxbuttons',
        'jsf-fields-range', 'jsf-fields-imageselect', 'jsf-fields-iconselect',
        'jsf-fields-fieldset', 'jsf-fields-advancedfieldset', 'jsf-fields-authfieldset',
        'jsf-fields-section', 'jsf-fields-actions', 'jsf-fields-array',
        'jsf-fields-array-simple', 'jsf-fields-tabarray', 'jsf-fields-tabarray-maxitems',
        'jsf-fields-tabarray-value', 'jsf-fields-selectfieldset', 'jsf-fields-selectfieldset-key',
        'jsf-fields-submit', 'jsf-fields-help', 'jsf-fields-hidden',
        'jsf-fields-questions', 'jsf-templating-idx', 'jsf-templating-value',
        'jsf-templating-values', 'jsf-templating-tpldata', 'jsf-events',
        'jsf-previousvalues', 'jsf-previousvalues-multidimensional',
      ],
      'ng2jsf': [
        'ng2jsf-simple-array', 'ng2jsf-data-only', // 'ng2jsf-layout-only',
        'ng2jsf-json-schema-draft04', 'ng2jsf-json-schema-draft03',
      ],
    },
    examples: {
      'asf': {
        'asf-simple': 'Simple',
        'asf-basic-json-schema-type': 'Basic JSON Schema Type',
        'asf-bootstrap-grid': 'Bootstrap Grid',
        'asf-complex-key-support': 'Complex Key Support',
        'asf-array': 'Array',
        'asf-tab-array': 'Tab Array',
        'asf-titlemap-examples': 'TitleMap Examples',
        'asf-kitchen-sink': 'Kitchen Sink',
        'asf-hack-conditional-required': 'Hack: Conditional Required',
      },
      'rjsf': {
        'rjsf-simple': 'Simple',
        'rjsf-nested': 'Nested',
        'rjsf-arrays': 'Arrays',
        'rjsf-numbers': 'Numbers',
        'rjsf-widgets': 'Widgets',
        'rjsf-ordering': 'Ordering',
        'rjsf-references': 'References',
        'rjsf-custom': 'Custom',
        'rjsf-errors': 'Errors',
        'rjsf-large': 'Large',
        'rjsf-date-and-time': 'Date & Time',
        'rjsf-validation': 'Validation',
        'rjsf-files': 'Files',
      },
      'jsf': {
        'jsf-gettingstarted': 'Getting started',
        'jsf-schema-basic': 'JSON Schema - A basic example',
        'jsf-schema-morecomplex': 'JSON Schema - Slightly more complex example',
        'jsf-schema-array': 'JSON Schema - Arrays',
        'jsf-schema-required': 'JSON Schema - Required field',
        'jsf-schema-default': 'JSON Schema - Default values',
        'jsf-schema-inlineref': 'JSON Schema - Inline $ref to definitions',
        'jsf-fields-common': 'Fields - Common properties',
        'jsf-fields-password': 'Fields - Gathering secrets: the password type',
        'jsf-fields-textarea': 'Fields - Large text: the textarea type',
        'jsf-fields-autocomplete': 'Fields - text field with jquery-ui autocomplete',
        'jsf-fields-ace': 'Fields - Code (JavaScript, JSON...): the ace type',
        'jsf-fields-color': 'Fields - Color picker: the color type',
        'jsf-fields-checkbox': 'Fields - Boolean flag: the checkbox type',
        'jsf-fields-checkboxes': 'Fields - Multiple options: the checkboxes type',
        'jsf-fields-select': 'Fields - Selection list: the select type',
        'jsf-fields-radios': 'Fields - A list of radio buttons: the radios type',
        'jsf-fields-radiobuttons': 'Fields - Radio buttons as real buttons: the radio buttons type',
        'jsf-fields-checkboxbuttons': 'Fields - Checkbox buttons: the checkbox buttons type',
        'jsf-fields-range': 'Fields - Number: the range type',
        'jsf-fields-imageselect': 'Fields - Image selector: the imageselect type',
        'jsf-fields-iconselect': 'Fields - Icon selector: the iconselect type',
        'jsf-fields-fieldset': 'Fields - Grouping: the fieldset type',
        'jsf-fields-advancedfieldset': 'Fields - Advanced options section: the advancedfieldset type',
        'jsf-fields-authfieldset': 'Fields - Authentication settings section: the authfieldset type',
        'jsf-fields-section': 'Fields - Generic group: the section type',
        'jsf-fields-actions': 'Fields - Group of buttons: the actions type',
        'jsf-fields-array': 'Fields - Generic array: the array type (complex)',
        'jsf-fields-array-simple': 'Fields - Generic array: the array type (simple)',
        'jsf-fields-tabarray': 'Fields - Arrays with tabs: the tabarray type',
        'jsf-fields-tabarray-maxitems': 'Fields - Arrays with tabs: the tabarray type w/ maxItems',
        'jsf-fields-tabarray-value': 'Fields - Arrays with tabs: the tabarray type w/ default & legend',
        'jsf-fields-selectfieldset': 'Fields - Alternative: the selectfieldset type',
        'jsf-fields-selectfieldset-key': 'Fields - Alternative with schema key',
        'jsf-fields-submit': 'Fields - Submit the form: the submit type',
        'jsf-fields-help': 'Fields - Guide users: the help type',
        'jsf-fields-hidden': 'Fields - Hidden form values: the hidden type',
        'jsf-fields-questions': 'Fields - Series of questions: the questions type',
        'jsf-templating-idx': 'Templating - item index with idx',
        'jsf-templating-value': 'Templating - tab legend with value and valueInLegend',
        'jsf-templating-values': 'Templating - values.xxx to reference another field',
        'jsf-templating-tpldata': 'Templating - Using the tpldata property',
        'jsf-events': 'Using event handlers',
        'jsf-previousvalues': 'Using previously submitted values',
        'jsf-previousvalues-multidimensional': 'Using previously submitted values - Multidimensional arrays',
      },
      'ng2jsf': {
        'ng2jsf-simple-array': 'Simple Array',
        'ng2jsf-data-only': 'Data Only (no Schema or Layout)',
        'ng2jsf-layout-only': 'Layout Only (no Schema or Data)',
        'ng2jsf-json-schema-draft04': 'JSON Meta-Schema - Version 4',
        'ng2jsf-json-schema-draft03': 'JSON Meta-Schema - Version3',
      },
    },
    links: {
      'asf': { 'url': 'http://schemaform.io/examples/bootstrap-example.html', },
      'rjsf': { 'url': 'https://mozilla-services.github.io/react-jsonschema-form/', },
      'jsf': { 'url': 'http://ulion.github.io/jsonform/playground/',
        'suffixes': {
          'jsf-gettingstarted': '?example=gettingstarted',
          'jsf-schema-basic': '?example=schema-basic',
          'jsf-schema-morecomplex': '?example=schema-morecomplex',
          'jsf-schema-array': '?example=schema-array',
          'jsf-schema-required': '?example=schema-required',
          'jsf-schema-default': '?example=schema-default',
          'jsf-schema-inlineref': '?example=schema-inlineref',
          'jsf-fields-common': '?example=fields-common',
          'jsf-fields-password': '?example=fields-password',
          'jsf-fields-textarea': '?example=fields-textarea',
          'jsf-fields-autocomplete': '?example=fields-autocomplete',
          'jsf-fields-ace': '?example=fields-ace',
          'jsf-fields-color': '?example=fields-color',
          'jsf-fields-checkbox': '?example=fields-checkbox',
          'jsf-fields-checkboxes': '?example=fields-checkboxes',
          'jsf-fields-select': '?example=fields-select',
          'jsf-fields-radios': '?example=fields-radios',
          'jsf-fields-radiobuttons': '?example=fields-radiobuttons',
          'jsf-fields-checkboxbuttons': '?example=fields-checkboxbuttons',
          'jsf-fields-range': '?example=fields-range',
          'jsf-fields-imageselect': '?example=fields-imageselect',
          'jsf-fields-iconselect': '?example=fields-iconselect',
          'jsf-fields-fieldset': '?example=fields-fieldset',
          'jsf-fields-advancedfieldset': '?example=fields-advancedfieldset',
          'jsf-fields-authfieldset': '?example=fields-authfieldset',
          'jsf-fields-section': '?example=fields-section',
          'jsf-fields-actions': '?example=fields-actions',
          'jsf-fields-array': '?example=fields-array',
          'jsf-fields-tabarray': '?example=fields-tabarray',
          'jsf-fields-tabarray-maxitems': '?example=fields-tabarray-maxitems',
          'jsf-fields-tabarray-value': '?example=fields-tabarray-value',
          'jsf-fields-selectfieldset': '?example=fields-selectfieldset',
          'jsf-fields-selectfieldset-key': '?example=fields-selectfieldset-key',
          'jsf-fields-submit': '?example=fields-submit',
          'jsf-fields-help': '?example=fields-help',
          'jsf-fields-hidden': '?example=fields-hidden',
          'jsf-fields-questions': '?example=fields-questions',
          'jsf-templating-idx': '?example=templating-idx',
          'jsf-templating-value': '?example=templating-value',
          'jsf-templating-values': '?example=templating-values',
          'jsf-templating-tpldata': '?example=templating-tpldata',
          'jsf-events': '?example=events',
          'jsf-previousvalues': '?example=previousvalues',
          'jsf-previousvalues-multidimensional': '?example=previousvalues-multidimensional',
        },
      },
    },
    frameworkList: [ 'bootstrap-3', 'material-design', 'no-framework' ],
    frameworks: {
      'bootstrap-3': 'Bootstrap 3 framework',
      'material-design': 'Material Design framework (under construction)',
      'no-framework': 'No Framework (bare controls + styles from layout only)',
    },
  };
  private selectedSet: string = 'asf';
  private selectedExample: string = 'asf-basic-json-schema-type';
  private selectedFramework: string = 'bootstrap-3';

  private formActive: boolean = false;
  private aceHeight: number = 600;
  private jsonFormSchema: string;
  private jsonFormValid: boolean = false;
  private jsonFormErrorMessage: string = 'Loading form...';
  private jsonFormObject: any;
  private jsonFormOptions: any = {
    addSubmit: true, // Add a submit button if layout does not have one
    loadExternalAssets: true, // Load external css and JavaScript for frameworks
    formDefaults: { feedback: true }, // SHow inline feedback icons
    debug: false,
  };
  private liveFormData: any = {};
  private formValidationErrors: any;
  private formIsValid: boolean = null;
  private submittedFormData: any = null;
  private aceEditorOptions: any = {
    highlightActiveLine: true,
    maxLines: 1000,
    printMargin: false,
    autoScrollEditorIntoView: true,
  };

  constructor(
    private route: ActivatedRoute,
    private router: Router,
    private http: Http,
  ) { }

  ngOnInit() {
    // Checks query string for the name of a form to load
    this.route.queryParams.subscribe(
      params => {
        if (params['set']) { this.selectedSet = params['set']; }
        if (params['example']) { this.selectedExample = params['example']; }
        if (params['framework']) { this.selectedFramework = params['framework']; }
      }
    );
  }

  ngAfterViewInit() {
    this.loadSelectedExample();
  }

  onSubmit(data: any) {
    this.submittedFormData = data;
  }

  get prettySubmittedFormData() {
    return JSON.stringify(this.submittedFormData, null, 2);
  }

  onChanges(data: any) {
    this.liveFormData = data;
  }

  get prettyLiveFormData() {
    return JSON.stringify(this.liveFormData, null, 2);
  }

  private isValid(isValid: boolean): void {
    this.formIsValid = isValid;
  }

  private validationErrors(data: any): void {
    this.formValidationErrors = data;
  }

  get prettyValidationErrors() {
    if (!this.formValidationErrors) { return null; }
    let prettyValidationErrors = '';
    for (let error of this.formValidationErrors) {
      prettyValidationErrors += (error.dataPath.length ?
        error.dataPath.slice(1) + ' ' + error.message : error.message) + '\n';
    }
    return prettyValidationErrors;
  }

  private resizeAceEditor() {
    this.aceHeight = window.innerHeight - 230;
  }

  private loadSelectedSet(selectedSet?: string) {
    if (selectedSet && selectedSet !== this.selectedSet) {
      this.selectedSet = selectedSet;
      this.selectedExample = this.examples.exampleList[selectedSet][0];
      this.router.navigateByUrl(
        '/?set=' + selectedSet +
        '&example=' + this.selectedExample +
        '&framework=' + this.selectedFramework
      );
      this.loadSelectedExample();
    }
  }

  // Load and display the selected schema
  // (runs whenever the user selects a schema from the drop-down menu)
  private loadSelectedExample(selectedSet?: string, selectedExample?: string) {
    if (selectedExample && selectedExample !== this.selectedExample) {
      this.selectedSet = selectedSet;
      this.selectedExample = selectedExample;
      this.router.navigateByUrl(
        '/?set=' + selectedSet +
        '&example=' + selectedExample +
        '&framework=' + this.selectedFramework
      );
      this.liveFormData = {};
      this.submittedFormData = null;
      this.formIsValid = null;
      this.formValidationErrors = null;
    }
    this.http
      .get('src/playground/examples/' + this.selectedExample + '.json')
      .map(schema => schema.text())
      .subscribe(schema => {
        this.jsonFormSchema = schema;
        this.generateForm(this.jsonFormSchema);
      });
  }

  private loadSelectedFramework(selectedFramework: string) {
    this.router.navigateByUrl(
      '/?set=' + this.selectedSet +
      '&example=' + this.selectedExample +
      '&framework=' + selectedFramework
    );
    this.generateForm(this.jsonFormSchema);
  }

  // Display the form entered by the user
  // (runs whenever the user changes the jsonform object in the ACE input field)
  private generateForm(newFormString: string) {
    if (!newFormString) { return; }
    this.formActive = false;
    this.liveFormData = {};
    this.submittedFormData = null;

    // Most examples should be written in pure JSON, but if a schema includes
    // a function, the playground will compile it as Javascript instead
    try {

      // Parse entered content as JSON
      this.jsonFormObject = JSON.parse(newFormString);
      this.jsonFormValid = true;
    } catch (jsonError) {
      try {

        // If entered content is not valid JSON,
        // parse as JavaScript instead to include functions
        let newFormObject: any = null;
        eval('newFormObject = ' + newFormString);
        this.jsonFormObject = newFormObject;
        this.jsonFormValid = true;
      } catch (javascriptError) {

        // If entered content is not valid JSON or JavaScript, show error
        this.jsonFormValid = false;
        this.jsonFormErrorMessage =
          'Entered content is not currently a valid JSON Form object.\n' +
          'As soon as it is, you will see your form here. So keep typing. :-)\n\n' +
          'JavaScript parser returned:\n\n' + jsonError;
        return;
      }
    }
    this.formActive = true;
  }
}
