/********************************************************************************
 * Copyright (c) 2015-2018 Contributors to the Eclipse Foundation
 *
 * See the NOTICE file(s) distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 ********************************************************************************/


import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DatePipe } from '@angular/common';

import { TreeNode } from 'primeng/api';
import { TreeTable } from 'primeng/primeng';
import { Observable } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';

import { Node, Attribute, ContextGroup } from '@navigator/node';
import { NavigatorService } from '@navigator/navigator.service';
import { MDMNotificationService } from '@core/mdm-notification.service';
import { TRANSLATE } from '@core/mdm-core.module';
import { FileService } from '@file-explorer/services/file.service';
import { FileLinkContextWrapper } from '@file-explorer/model/file-explorer.model';
import { AuthenticationService } from '../../../authentication/authentication.service';

import { Sensor, Components, Context, ContextAttributeIdentifier} from '../../model/details.model';
import { ContextService } from '../../services/context.service';
import { Role } from 'src/app/authentication/authentication.service';

@Component({
  selector: 'mdm-detail-context',
  templateUrl: 'mdm-detail-descriptive-data.component.html',
  styleUrls: ['mdm-detail-descriptive-data.component.css'],
})

export class MDMDescriptiveDataComponent implements OnInit {

  private readonly StatusLoading = TRANSLATE('details.mdm-detail-descriptive-data.status-loading');
  private readonly StatusSaving = TRANSLATE('details.mdm-detail-descriptive-data.status-saving');
  private readonly StatusNoNodes = TRANSLATE('details.mdm-detail-descriptive-data.status-no-nodes-available');
  private readonly StatusNoDescriptiveData = TRANSLATE('details.mdm-detail-descriptive-data.status-no-descriptive-data-available');

  public treeNodes: {[key: string]: TreeNode[]};

  // this holds the type dependant original context data in case of cancelling the edit mode
  private tmpTreeNodes: Node[];

  public selectedNode: Node;
  public contextType: string;

  public contextComponents: Components;
  public sensors: Sensor[];
  public status: string;

  // reference to be able to use enum in html template
  public contextGroupEnum = ContextGroup;

  public editMode: boolean;

  public isTreeTableExpanded = true;

  constructor(private route: ActivatedRoute,
              private _contextService: ContextService,
              private navigatorService: NavigatorService,
              private notificationService: MDMNotificationService,
              private translateService: TranslateService,
              private datePipe: DatePipe,
              private authenticationService: AuthenticationService,
              private fileService: FileService) {
  }

  public canEdit: boolean;

  ngOnInit() {
    this.authenticationService.isUserInRole([Role.Admin.toString(), Role.User.toString()]).subscribe(b => this.canEdit = b);
    this.status = this.StatusLoading;
    this.editMode = false;

    this.refreshDetailData(this.navigatorService.getSelectedNode());
    this.route.params
      .subscribe(
        params => this.refreshContextData(params['context']),
          error => this.notificationService.notifyError(
            this.translateService.instant('details.mdm-detail-descriptive-data.err-cannot-load-scope'), error));

    // node changed from the navigation tree
    this.navigatorService.selectedNodeChanged
        .subscribe(
          node => this.refreshDetailData(node),
          error => this.notificationService.notifyError(
            this.translateService.instant('details.mdm-detail-descriptive-data.err-cannot-load-data'), error));

    // file changed
    this.fileService.onFileChanged().subscribe(link => this.handleFileChanged(link));
  }

  handleFileChanged(fileLinkContextWrapper: FileLinkContextWrapper) {
    if (this.treeNodes != undefined) {
      this.treeNodes[fileLinkContextWrapper.contextType]
          .filter(tnode => tnode.label === fileLinkContextWrapper.contextComponent.name)
          .map(tnode => tnode.children)
          .reduce((a, b) => a.concat(b), [])
          .filter(tnode => tnode.data.attribute.name === fileLinkContextWrapper.attribute.name)
          .forEach(tnode => tnode.data.attribute = fileLinkContextWrapper.attribute);
      // spread is necessary for treeTable changeDetection
      this.treeNodes[fileLinkContextWrapper.contextType] = [...
        this.treeNodes[fileLinkContextWrapper.contextType]];
    }
  }

  setContext(context: string) {
    let contextType: string;

    switch (context) {
      case 'uut':
        contextType = 'UNITUNDERTEST';
        break;
      case 'te':
        contextType = 'TESTEQUIPMENT';
        break;
      case 'ts':
        contextType = 'TESTSEQUENCE';
        break;
    }
    this.contextType = contextType;
  }

  /**
   * Listener method to change the context tab
   *
   * @param contextType
   */
  refreshContextData(contextType: string) {
    // revert before changing the context
    this.undoEditChanges(undefined, this.editMode);
    this.setContext(contextType);
    this.editMode = false;
  }

  /**
   * Listener method to change the node
   *
   * @param node
   */
  refreshDetailData(node: Node) {
    if (node != undefined) {
      this.selectedNode = node;
      this.status = this.StatusLoading;
      this.editMode = false;
      this.contextComponents = undefined;
      this.treeNodes = undefined;
      if (node.type.toLowerCase() === 'measurement' || node.type.toLowerCase() === 'teststep' || node.type.toLowerCase() === 'test') {
        this.loadContext(node);
      } else {
        this.status = this.StatusNoDescriptiveData;
      }
    } else {
      this.status = this.StatusNoNodes;
    }
  }

  /**
   * Load the context data for the provided node
   *
   * @param node
   */
  private loadContext(node: Node) {
    this._contextService.getContext(node).subscribe(
      components => {
          if (components['UNITUNDERTEST'] != undefined
              || components['TESTEQUIPMENT'] != undefined
              || components['TESTSEQUENCE'] != undefined) {
                this.contextComponents = components;
                this.treeNodes = this.mapComponents(components);
              } else {
                this.status = this.StatusNoDescriptiveData;
              }
        },
        error => this.notificationService.notifyError(
          this.translateService.instant('details.mdm-detail-descriptive-data.err-cannot-load-context'), error)
      );
  }

  getIdentifier(contextDescribable: Node, contextComponent: Node, attribute: Attribute, contextGroup?: ContextGroup, contextType?: string) {
    return new ContextAttributeIdentifier(contextDescribable, contextComponent, attribute, contextGroup, contextType);
  }

  getNodeClass(item: Node) {
    return 'icon ' + item.type.toLowerCase();
  }

  /**
   * Change the tree state to expanded or collapsed
   *
   * @param type
   * @param expand
   */
  toggleTreeNodeState(tt: TreeTable) {
    this.isTreeTableExpanded = !this.isTreeTableExpanded;
    const nodeArray = this.treeNodes[this.contextType];
    if (nodeArray != undefined) {
      for (let node of nodeArray) {
        this.recursiveChangeNodes(node, this.isTreeTableExpanded);
      }
    }

    // invoke table update when pressing the plus or minus buttons from the table header
    tt.updateSerializedValue();
    tt.tableService.onUIUpdate(tt.value);
  }

  /**
   * Change the tree node state recursively
   *
   * @param node
   * @param expand
   */
  recursiveChangeNodes(node: TreeNode, expand: boolean) {
    node.expanded = expand;
    if (node.children != undefined && node.children.length > 0) {
      for (let child of node.children) {
        this.recursiveChangeNodes(child, expand);
      }
    }
  }

  /**
   * Get the nodes from the current context
   *
   * @param nodes
   * @param parentId optional parent id which will get the child nodes
   */
  getNodes(nodes: Node[], parentId: string) {
    return nodes.filter(n => this.nodeIsInCurrentContext(n, parentId));
  }

  nodeIsInCurrentContext(node: Node, parentId: string) {
    let parentNodeId = node.relations != null && node.relations.length > 0 ? node.relations[0].parentId : null;
    return parentId == null && parentNodeId == null
          || parentId != null && parentNodeId != null && parentId === parentNodeId;
  }

  /**
   * Create a tree node based on the mdm entity
   *
   * @param node
   * @param context
   */
  createTreeNode(node: Node, children: Node[]) {
    return <TreeNode>{
      label: node.name,
      data: {
        'name': node.name,
        'attribute': node,
        'header': true
      },
      children: this.createTreeChildren(node, children),
      icon: this.getNodeClass(node),
      expanded: true
    };
  }

  /**
   * Create the tree children nodes recursive based on the mdm attributes and subsequent mdm entities
   *
   * @param node the current node
   * @param contexts the complete contexts
   */
  createTreeChildren(node: Node, children: Node[]) {
    let list = [];

    for (let attribute of node.attributes) {
      let tmp = <TreeNode>{
        data: {
          'name': attribute.name,
          'attribute': this.patchAttributeForDate(attribute),
          'header': false
        },
        expanded: true
      };
      list.push(tmp);
    }

    if (node.relations != null && node.relations.length > 0) {
      for (let relation of node.relations) {
        if (relation.ids != null && relation.ids.length > 0) {
          for (let id of relation.ids) {
            let nodes = this.getNodes(children, id);
            for (let n of nodes) {
              list.push(this.createTreeNode(n, children));
            }
          }
        }
      }
    }
    return list;
  }

  /**
   * Method to create a tree structure from the flat context entity and attribute map
   *
   * @param components
   */
  mapComponents(components: Components) {
    const list: {[key: string]: TreeNode[]} = {};
    if (components != undefined ) {
      for (let key of Object.keys(components)) {
        const nodes: Node[] = this.getNodes(components[key], null);
        if (nodes != undefined) {
          list[key] = nodes.map(node => this.createTreeNode(node, components[key]));
        }
      }
    }
    return list;
  }

  /**
   * Convert the date for UI or backend
   *
   * @param attribute
   */
  patchAttributeForDate(attribute: Attribute) {
    if (attribute.dataType != null && attribute.dataType.length > 0 && 'DATE' === attribute.dataType) {
      const val = attribute.value as any[];
      if (val != null && val.length > 0) {
        if (val[0] != null && val[0].length > 0) {
          val[0] = this.convertFixedDateStr(val[0], true);
        }
        if (val.length > 1 && val[1] != null && val[1].length > 0) {
          val[1] = this.convertFixedDateStr(val[1], true);
        }
      }
    }
    return attribute;
  }

  /** *********************
   * Edit functions start
   ********************** */

  convertFixedDateStr(dt: string, convertForUI: boolean) {
    let newDt = dt;
    let sourceFormat = '';

    /**
     * Get the translation immediately
     */
    sourceFormat = this.translateService.instant('details.mdm-detail-descriptive-data.transform-dateformat');

    if (dt != null && dt.length > 0 && convertForUI && dt.indexOf('T') > -1) {
      // for display purpose
      let tmpDt = this.parseISOString(dt);
      newDt = this.datePipe.transform(tmpDt, sourceFormat, '+0000');
    } else if (dt != null && dt.length > 0 && !convertForUI && dt.indexOf('T') === -1) {
      // re-convert UI date to server date for persistence
      if (newDt.indexOf('-') === -1) {
        // find the date patterns dd, MM and yyyy and grab the according index positions
        let startDay = sourceFormat.indexOf('d');
        let endDay = sourceFormat.lastIndexOf('d');
        let startMonth = sourceFormat.indexOf('M');
        let endMonth = sourceFormat.lastIndexOf('M');
        let startYear = sourceFormat.indexOf('y');
        let endYear = sourceFormat.lastIndexOf('y');
        // manually attach the time as toISOString() will not properly transform the winter/summer time
        newDt = dt.substring(startYear, endYear + 1) + '-' + dt.substring(startMonth, endMonth + 1)
                  + '-' + dt.substring(startDay, endDay + 1);
        if (dt.indexOf(' ') > -1) {
          // use the provided timestamp
          newDt = newDt + 'T' + dt.substring(dt.indexOf(' ') + 1) + ':00Z';
        } else {
          newDt = newDt + 'T00:00:00Z';
        }
        if (newDt.length !== 20) {
          newDt = '';
        }
      }
    }
    return newDt;
  }

  /**
   * Fixed parsing for ISO date string
   *
   * @param s
   */
  parseISOString(s: string) {
    let b: any[] = s.split(/\D+/);
    return new Date(Date.UTC(b[0], --b[1], b[2], b[3], b[4], b[5], b[6]));
  }

  /**
   * Send the changed data to the backend
   *
   * @param node
   * @param type
   */
  private putContext(node: Node, type: string) {
    if (type == null) {
      return;
    }
    this.status = this.StatusSaving;
    this.treeNodes = undefined;

    const data = new Context();
    data.ordered = new Components();
    data.ordered[type] = this.getNodesWithUpdatedContent(this.contextComponents[type] as Node[], true);

    data.measured = new Components();
    data.measured[type] = this.getNodesWithUpdatedContent(this.contextComponents[type] as Node[], false);

    // clear for status display
    this.contextComponents = undefined;

    this._contextService.putContext(node, data).subscribe(
      components => {
        if (components.hasOwnProperty('UNITUNDERTEST')
          || components.hasOwnProperty('TESTEQUIPMENT')
          || components.hasOwnProperty('TESTSEQUENCE')) {
          this.contextComponents = components;
          this.treeNodes = this.mapComponents(this.contextComponents);
        } else {
          this.status = this.StatusNoDescriptiveData;
        }
      },
      error => this.notificationService.notifyError(
        this.translateService.instant('details.mdm-detail-descriptive-data.err-cannot-load-context'), error)
    );
  }

  onEdit(event: Event) {
    event.stopPropagation();
    this.editMode = true;
    this.tmpTreeNodes = JSON.parse(JSON.stringify(this.contextComponents[this.contextType]));
  }

  onCancelEdit(event: Event) {
    event.stopPropagation();
    this.editMode = false;
    this.isTreeTableExpanded = true;
    this.undoEditChanges(this.contextType, true);
  }

  onSaveChanges(event: Event) {
    event.stopPropagation();
    this.editMode = false;
    this.isTreeTableExpanded = true;
    this.putContext(this.selectedNode, this.contextType);
    this.tmpTreeNodes = undefined;
  }

  /**
   * Method to revert table changes back to the original state
   *
   * @param type
   */
  undoEditChanges(type: string, editMode: boolean) {
    this.refreshDetailData(this.navigatorService.getSelectedNode());
    // if (this.contextComponents != undefined && editMode && this.tmpTreeNodes != undefined) {
    //   if (type == undefined) {
    //       type = this.contextType;
    //   }
    //   // contexts is the origin, so we revert this back as the tree attributes are just references
    //   this.contextComponents[type] = this.tmpTreeNodes;
    //   // revert back
    //   this.treeNodes = this.mapComponents(this.contextComponents);
    //   this.tmpTreeNodes = null;
    // }
  }

  /**
   * Get the updated nodes from the current context
   *
   * @param contextComponents
   * @param type the context type
   * @param ordered true if ordered data, false if measured data
   */
  getNodesWithUpdatedContent(contextComponents: Node[], ordered: boolean) {
    let list = [];
    for (let component of contextComponents) {
      let parentNodeId = component.relations != null && component.relations.length > 0 ? component.relations[0].parentId : null;
      if (parentNodeId == null) {
        let attrs = [];
        for (let cAttribute of component.attributes) {
          let attr = new Attribute();
          let addAttr = true;
          attr.dataType = cAttribute.dataType;
          attr.name = cAttribute.name;
          attr.unit = cAttribute.unit;
          attr.value = '';

          if (ordered && cAttribute.value instanceof Array && cAttribute.value.length > 0) {
            attr.value = cAttribute.value[0];
          } else if (!ordered && cAttribute.value instanceof Array && cAttribute.value.length > 1) {
            attr.value = cAttribute.value[1];
          }
          // lookup new value from treenodes
          if (attr.dataType === 'BOOLEAN' && attr.value != null && attr.value.toString().length > 0) {
            attr.value = attr.value.toString() === 'true' ? '1' : '0';
          }

          // BUG: don't add if non-string as this throws an parsing error in the middleware
          if (attr.dataType !== 'STRING' && (attr.value == null || attr.value.toString().length === 0)) {
            addAttr = false;
          }

          if (addAttr && attr.dataType === 'DATE') {
            attr.value = this.convertFixedDateStr(attr.value as string, false);
          }

          if (addAttr) {
            if (this.isAttributeValueModified(attr, component, ordered)) {
              attrs.push(attr);
            }
          }
        }
        // un-merged list
        if (attrs.length > 0) {
          let c = JSON.parse(JSON.stringify(component));
          c.attributes = attrs;
          list.push(c);
        }
      }
    }
    return list;
  }

  private isAttributeValueModified(attr: Attribute, component: Node, ordered: boolean) {
    for (let tmpNode of this.tmpTreeNodes) {
      if (tmpNode.name === component.name) {
        for (let attribute of tmpNode.attributes) {
          if (attribute.name === attr.name && attribute.value instanceof Array) {
            let orgValue = ordered ? attribute.value[0] :
            attribute.value.length > 1 ? attribute.value[1] : undefined;
            if (orgValue != undefined) {
              if (attr.dataType === 'BOOLEAN') {
                // server value = true or false, UI value = 1 or 0
                return attr.value === '0' && orgValue === 'true'
                  || attr.value === '1' && orgValue === 'false'
                  || attr.value !== '' && orgValue === '';
              } else {
                // plain comparison
                return attr.value !== orgValue;
              }
            }
            return false;
          }
        }
      }
    }
  }

  /** *********************
   * Edit functions end
   ********************** */

}
