import { GrupoConectorInterface } from 'src/app/interfaces/samwf/grupo-conector-interface';
import {
  Component,
  ChangeDetectionStrategy,
  ViewChild,
  ViewEncapsulation,
  OnInit,
} from '@angular/core';
import {
  DiagramComponent,
  NodeModel,
  ConnectorModel,
  PaletteModel,
  BasicShapeModel,
  MarginModel,
  NodeConstraints,
  AnnotationConstraints,
  ConnectorConstraints,
  PointModel,
  FlowShapeModel,
  StraightSegmentModel,
  IDragEnterEventArgs,
  INode,
  IConnectionChangeEventArgs,
  ZoomOptions,
  IClickEventArgs,
  ICollectionChangeEventArgs,
} from '@syncfusion/ej2-angular-diagrams';

import { ExpandMode } from '@syncfusion/ej2-navigations';
import { BreakpointObserver } from '@angular/cdk/layout';
import { TaskInterface } from 'src/app/interfaces/samwf/task-interface';
import { EmpleadoInterface } from 'src/app/interfaces/samwf/empleado-interface';
import { MatSnackBar } from '@angular/material/snack-bar';
import { NodeinfoInterface } from 'src/app/interfaces/samwf/nodeinfo-interface';
import { WorkflowService } from 'src/app/services/samwf/workflow.service';
import { lastValueFrom } from 'rxjs';

@Component({
  selector: 'app-workflow-diagrama',
  templateUrl: './workflow-diagrama.component.html',
  styleUrls: ['./workflow-diagrama.component.css'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  encapsulation: ViewEncapsulation.None,
})
export class WorkflowDiagramaComponent implements OnInit {
  //DIAGRAM COMPONENT
  @ViewChild('diagram')
  diagram:
    | DiagramComponent
    //LOADING
    | undefined;

  //LOADING
  loading: boolean = false;
  canUpdate: boolean = true;
  isSecuencia: boolean = false;
  procesos_secuencia: any = [];
  conectores_base: any[] = [];
  grupos_conectores: GrupoConectorInterface[] = [];
  showFiller = false;
  pantallaGrande: Boolean = !this.breakpointObserver.isMatched(
    '(max-width: 1700px)'
  );

  hasNotificaciones: boolean = false;
  procesoSeleccionado: string = '';
  empleadoSeleccionado: string = '';
  nodoSeleccionado: NodeModel = {} as NodeModel;
  nodoDrag: INode = {} as INode;

  procesos: TaskInterface[] = [
    /* { id: 0, name: 'Iniciar proceso', isAvailable: false },
    { id: 1, name: 'Validar solicitud', isAvailable: true },
    { id: 7, name: 'Aprobar solicitud', isAvailable: false },
    { id: 8, name: 'Rechazado', isAvailable: false },
    { id: 9, name: 'Pendiente de aprobación', isAvailable: false },
    { id: 15, name: 'Aprobado', isAvailable: false },
    { id: 1000, name: 'Fin', isAvailable: false },
 */
  ];

  empleados: EmpleadoInterface[] = [
    { id: 1, name: 'Alan Garcia' },
    { id: 2, name: 'Fer Alpuche' },
    { id: 3, name: 'Omar Santamaria' },
  ];

  // Fin reglas

  // Olds
  old_nodes: any[] = [];

  // Constraints
  nodeConstraints: NodeConstraints | undefined;
  notaConstraints: NodeConstraints | undefined;
  annotationConstraints: AnnotationConstraints | undefined;
  connectorConstraints: ConnectorConstraints | undefined;

  expandMode: ExpandMode | undefined;
  palettes: PaletteModel[] | undefined;
  symbolMargin: MarginModel | undefined;

  sourcePoint: PointModel | undefined;
  targetPoint: PointModel | undefined;
  segments: StraightSegmentModel | undefined;

  // Shapes
  shape_inicio: FlowShapeModel = { type: 'Flow', shape: 'Terminator' };
  shape_data: FlowShapeModel = { type: 'Flow', shape: 'Data' };
  shape_decision: FlowShapeModel = { type: 'Flow', shape: 'Decision' };
  shape_process: FlowShapeModel = { type: 'Flow', shape: 'Process' };
  shape_fin: FlowShapeModel = { type: 'Flow', shape: 'Terminator' };

  shape_connector_1: ConnectorModel = {} as ConnectorModel;

  constructor(
    private breakpointObserver: BreakpointObserver,
    private snackBar: MatSnackBar,
    private _samwfService: WorkflowService
  ) {}

  async ngOnInit() {
    await lastValueFrom(this._samwfService.getTasks()).then(
      (data: any) => {
        this.procesos = data.response;
      },
      (error: any) => console.log(error)
    );

    this.expandMode = 'Multiple';
    this.palettes = [
      {
        //Sets the id of the palette
        id: 'flow',
        //Sets whether the palette expands/collapse its children
        expanded: true,
        //Adds the palette items to palette
        symbols: this.getFlowShapes(),
        //Sets the header text of the palette
        title: 'Formas de flujo',
        iconCss: 'e-ddb-icons e-flow',
      },
      {
        id: 'connectors',
        expanded: true,
        symbols: this.getConnectors(),
        title: 'Conectores',
        iconCss: 'e-ddb-icons e-connector',
      },
    ];

    this.shape_connector_1 = {
      id: 'Link1',
      type: 'Orthogonal',
      sourcePoint: {
        x: 700,
        y: 370,
      },
      targetPoint: {
        x: 700,
        y: 430,
      },
      targetDecorator: {
        shape: 'Arrow',
      },
    };

    this.symbolMargin = {
      left: 10,
      right: 10,
      top: 15,
      bottom: 15,
    };

    this.sourcePoint = { x: 100, y: 100 };
    this.targetPoint = { x: 200, y: 200 };
    this.segments = { type: 'Orthogonal' };

    this.nodeConstraints =
      NodeConstraints.Select |
      NodeConstraints.Rotate |
      NodeConstraints.Resize |
      NodeConstraints.Drag |
      NodeConstraints.PointerEvents |
      NodeConstraints.Tooltip |
      NodeConstraints.ReadOnly;

    this.notaConstraints =
      NodeConstraints.Select |
      NodeConstraints.Rotate |
      NodeConstraints.Resize |
      NodeConstraints.Drag |
      NodeConstraints.PointerEvents |
      NodeConstraints.ReadOnly;

    this.connectorConstraints =
      ConnectorConstraints.Select |
      ConnectorConstraints.Drag |
      ConnectorConstraints.PointerEvents |
      ConnectorConstraints.DragSegmentThumb |
      ConnectorConstraints.DragSourceEnd |
      ConnectorConstraints.DragTargetEnd |
      ConnectorConstraints.ReadOnly;
  }

  validarSecuencia() {
    const nodes = this.diagram!.nodes as INode[];
    console.log(nodes);

    //Verificar que todos los nodos y conectores esten conectados
    //Inicio proceso (node1) si puede tener entradas vacias
    //Fin proceso son especiales

    //Math.max.apply(Math, myArr.map(o => o.x));
    /*var nums = [4, 9, 15, 6, 2], numero = 5;

    var cercano = nums.reduce(function(prev, curr) {
      return (Math.abs(curr - numero) < Math.abs(prev - numero) ? curr : prev);
    }); */
    console.log(
      !this.diagram!.connectors.some(
        (connnector) => connnector.sourceID == '' || connnector.targetID == ''
      )
    );

    if (
      !nodes.some(
        (node) =>
          node.inEdges.length == 0 && node.id != '0' && node.id != 'nota'
      ) &&
      !nodes.some(
        (node) =>
          node.outEdges.length == 0 && node.id != '21' && node.id != 'nota'
      ) &&
      !this.diagram!.connectors.some(
        (connnector) => connnector.sourceID == '' || connnector.targetID == ''
      )
    ) {
      this.getSecuencia();
    } else {
      this.snackBar.open('Verificar la conexión de los nodos', 'Cerrar', {
        duration: 3000,
      });
    }
  }

  getSecuencia() {
    //Mostrar procesos_secuencia
    this.isSecuencia = true;
    //Limpiar procesos_secuencia
    this.procesos_secuencia = [];
    //Variables
    let tipo_shape: any;
    let nombre_shape = '';
    let secuencia: any;
    let nodos_condicionales: Array<string>[] = [];

    console.log(nodos_condicionales);

    //Banderas
    let outEdge: string = '';

    this.diagram!.nodes.forEach((node) => {
      //Castear para obtener sus puertos de entrada y salida
      let node_node: INode = node as INode;

      //Sin puertos de entrada (Inicio)
      if (node_node.inEdges.length == 0) {
        outEdge = node_node.outEdges[0];
      } else {
        secuencia = this.generarSecuencia(nodos_condicionales, outEdge);

        nodos_condicionales = secuencia.nodos;
        outEdge = secuencia.out;
        node = secuencia.nodo;

        if (node.shape != undefined) {
          if (node.shape?.type?.includes('Flow')) {
            tipo_shape = node.shape as FlowShapeModel;
            nombre_shape = tipo_shape.shape;
          }
          if (node.shape?.type?.includes('Basic')) {
            tipo_shape = node.shape as BasicShapeModel;
            nombre_shape = tipo_shape.shape;
          }
          this.procesos_secuencia.push({
            shape: nombre_shape,
            content:
              this.procesos[
                this.procesos.findIndex(
                  (object) => object.name === node.annotations?.[0].content!
                )
              ],
            secuence: this.getNumeroSecuencia(node.annotations?.[0].content!),
          });
        }
      }
    });
    console.log(this.procesos_secuencia);

    this.procesos_secuencia.sort((a: any, b: any) => a.secuence - b.secuence);

    //this.loading = false;
    //this.diagram.saveDiagram()
    //console.log(this.diagram.saveDiagram());
  }

  generarSecuencia(nodos: Array<string>[], out: string): Object {
    const nodes = this.diagram!.nodes as INode[];

    let outEdge: string = out;
    let filtro_nodo: INode | undefined = {} as INode;
    let nodos_condicionales: Array<string>[] = nodos;
    let nodo_condicional: string[] = [];
    let direccion_condicional: any;
    let nodo: NodeModel = {} as NodeModel;

    console.log('Buscar: ' + outEdge);
    filtro_nodo = nodes.find((nodo) => nodo.inEdges.includes(outEdge));

    //Encontro al menos un valor en el filtro ?
    if (filtro_nodo) {
      //Es condición y si el siguiente valor también es condición, también se asignan mis variables?
      if (filtro_nodo.outEdges.length > 1) {
        console.log('Condicion');
        //Asignar los conectores condicionales
        nodos_condicionales.push([...filtro_nodo.outEdges]);
        //Obtener el orden de los nodos
        direccion_condicional = this.getNodosCondicionales(
          nodos_condicionales,
          outEdge
        );
        //Asignar el único valor
        outEdge = direccion_condicional.out;
        //Asignar todos los nodos
        nodos_condicionales = direccion_condicional.nodos;
        //Asignar el nodo con el nodo encontrado
        nodo = filtro_nodo as NodeModel;

        //Solo apunta  un solo componente
        // ¿Menor o igual a 1?
      } else if (filtro_nodo.outEdges.length > 0) {
        console.log('Normal');
        outEdge = filtro_nodo.outEdges[0];
        //Asignar el nodo con el nodo encontrado
        nodo = filtro_nodo as NodeModel;
        //Apunta al ultimo componente
      } else {
        direccion_condicional = this.getNodosCondicionales(
          nodos_condicionales,
          outEdge
        );

        outEdge = direccion_condicional.out;
        nodos_condicionales = direccion_condicional.nodos;
        nodo_condicional = direccion_condicional.nodo;

        if (nodo_condicional.length == 0 && nodos_condicionales.length == 1) {
          return this.generarSecuencia([], outEdge);
        } else {
          if (nodos_condicionales.length == 0 && nodo_condicional.length == 0) {
            return this.generarSecuencia([], '');
          } else {
            return this.generarSecuencia(nodos_condicionales, outEdge);
          }
        }
      }
    } else {
      console.log('ELSE');
    }

    return { nodos: nodos_condicionales, nodo: nodo, out: outEdge };
  }

  getNodosCondicionales(nodos: Array<string>[], out: string): Object {
    let outEdge: string = '';
    let nodos_condicionales: Array<string>[] = nodos;
    let nodo_condicional: string[] = [];

    if (nodos_condicionales.length > 0) {
      nodo_condicional = nodos_condicionales[nodos_condicionales.length - 1];
      if (nodo_condicional.length > 0) {
        outEdge = nodo_condicional.pop()!;
      } else {
        nodos_condicionales.pop()!;
        console.log(nodos_condicionales);
        console.log(out);

        return this.getNodosCondicionales(nodos_condicionales, out);
      }
    } else {
      outEdge = out;
    }

    return { nodos: nodos_condicionales, nodo: nodo_condicional, out: outEdge };
  }

  //Agregar componente al diagrama
  dragEnter(args: IDragEnterEventArgs): void {
    let isNode: boolean = args.dragItem.shape?.type?.includes('Flow')
      ? true
      : false;
    let obj: NodeModel = args.dragItem as NodeModel;

    if (isNode) {
      this.nodoSeleccionado = obj;
      let objDrag: INode = args.element as INode;
      this.nodoDrag = objDrag;

      if (!(this.empleadoSeleccionado == '') || this.hasNotificaciones) {
        obj.constraints = NodeConstraints.Default | NodeConstraints.Tooltip;
      }

      obj.addInfo = {
        secuence: 55,
        parentSecuence: 55,
        entries: 1,
        outputs: 1,
        numbersBefore: 1,
        numbersAfter: 1,
        notify: this.hasNotificaciones,
        process: this.procesoSeleccionado,
        employee: this.empleadoSeleccionado,
        isNode: true,
        canUpdate: true,
      };
    }
  }

  // ?
  clickNode(args: IClickEventArgs) {
    console.log('click');

    if (args.actualObject != undefined) {
      let node = args.actualObject as NodeModel;
      let info = node.addInfo as NodeinfoInterface;

      if (info != undefined && info.isNode) {
        this.nodoSeleccionado = node;
        this.canUpdate = info.canUpdate;
        this.procesoSeleccionado = info.process;
        this.empleadoSeleccionado = info.employee;
        this.hasNotificaciones = info.notify;
      } else {
        this.nodoSeleccionado = {};
        this.canUpdate = true;
        this.procesoSeleccionado = '';
        this.empleadoSeleccionado = '';
        this.hasNotificaciones = false;
      }
    } else {
      if (!(args instanceof PointerEvent)) {
        this.nodoSeleccionado = {};
        this.canUpdate = true;
        this.procesoSeleccionado = '';
        this.empleadoSeleccionado = '';
        this.hasNotificaciones = false;
      }
    }
  }

  collectionChange(args: ICollectionChangeEventArgs) {
    console.log(args);
  }

  //Verificar conexiones de Nodos (CON CONEXIONES RESTRINGIDAS)
  connectionChange(args: IConnectionChangeEventArgs): void {
    //Verificar el conector que se esta cambiando
    let connector = args.connector as any;

    //¿Esta conectado?
    if (connector.sourceID != '' && connector.targetID != '') {
      //SI LA NUEVA CONEXIÓN RESPETA LA ESTRUCTURA BASE NO ES NECESARIO VALIDAR
      if (
        !this.conectores_base.some(
          (conector) =>
            conector.source == connector.sourceID &&
            conector.target == connector.targetID
        )
      ) {
        //No se permite conectar más de 2 nodos que aún no tengan conexión con el diagrama
        //Verificar si la nueva conexión hace referencia al diagrama
        //Solo se permite UNA CONEXIÓN fuera del diagrama
        if (
          this.conectores_base.some(
            (conector) =>
              conector.source == connector.sourceID ||
              conector.target == connector.targetID
          )
        ) {
          let nodo_source = this.diagram!.getObject(
            connector.sourceID
          ) as NodeModel;

          let inodo_source = this.diagram!.getNodeObject(
            connector.sourceID
          ) as INode;

          let nodo_target = this.diagram!.getObject(
            connector.targetID
          ) as NodeModel;

          let inodo_target = this.diagram!.getNodeObject(
            connector.targetID
          ) as INode;

          let info_source = nodo_source.addInfo as NodeinfoInterface;
          let info_target = nodo_target.addInfo as NodeinfoInterface;

          if (
            this.conexionNodo(
              info_source,
              inodo_source.outEdges.length == 0
                ? 1
                : inodo_source.outEdges.length,
              info_target,
              inodo_target.inEdges.length == 0 ? 1 : inodo_target.inEdges.length
            )
          ) {
            info_target.parentSecuence = info_source.secuence;

            console.log('numberAfter ' + info_source.numbersAfter);
            console.log('numberBefore ' + info_source.numbersBefore);

            if (info_source.numbersAfter % 2 == 0) {
              info_target.secuence =
                Math.round(info_source.numbersAfter / 2) + 1;
              info_target.numbersAfter =
                Math.round(info_source.numbersAfter / 2) - 1;
              info_target.numbersBefore = Math.round(
                info_source.numbersAfter / 2
              );
            } else {
              info_target.secuence =
                Math.round(info_source.numbersAfter / 2) + 1;
              info_target.numbersAfter =
                Math.round(info_source.numbersAfter / 2) - 1;
              info_target.numbersBefore =
                Math.round(info_source.numbersAfter / 2) - 1;
            }

            nodo_target.addInfo = info_target;

            /*if (nodo_source.children != undefined) {
              if (!nodo_source.children.some(child => child.includes(connector.targetID))) {
                nodo_source.children.push(connector.targetID);
              }
            } else {
              nodo_source.children = [connector.targetID];
            }*/
          } else {
            args.connector.sourceID = '';
            args.connector.targetID = '';
          }
        } else {
          let inodo_source = this.diagram!.getNodeObject(
            connector.sourceID
          ) as INode;
          let inodo_target = this.diagram!.getNodeObject(
            connector.targetID
          ) as INode;

          /* if (
            (inodo_source.inEdges.length > 0 &&
              inodo_source.outEdges.length > 0) ||
            (inodo_target.inEdges.length > 0 &&
              inodo_target.outEdges.length > 0)
          ) {
            const conectores_source = this.conectores_base.map(
              (conector) => conector.source
            );
            const conectores_target = this.conectores_base.map(
              (conector) => conector.target
            );

            /*  console.log(inodo_source);
            console.log(conectores_source);

            console.log(
              inodo_source.inEdges.some((sourceInEdge) =>
                conectores_source.includes(sourceInEdge)
              ) ||
                inodo_source.outEdges.some((sourceInEdge) =>
                  conectores_source.includes(sourceInEdge)
                )
            );

            console.log(
              inodo_source.inEdges.find((sourceInEdge) =>
                conectores_source.includes(sourceInEdge)
              )
            );
            console.log(
              inodo_source.outEdges.find((sourceOutEdge) =>
                conectores_source.includes(sourceOutEdge)
              )
            );

            args.connector.sourceID = '';
            args.connector.targetID = '';
            this.snackBar.open(
              'Los nodos deben de estar conectados al diagrama',
              'Cerrar'
            );
          } */
        }
      }
    }
  }

  conexionNodo(
    sourceInfo: NodeinfoInterface,
    outputs: number,
    targetInfo: NodeinfoInterface,
    entries: number
  ): boolean {
    if (sourceInfo.numbersAfter < 1 || outputs > sourceInfo.outputs) {
      this.snackBar.open(
        'No es posible agregar conectores a "' +
          this.getNombreProceso(parseInt(sourceInfo.process)) +
          '"',
        'Cerrar'
      );
      return false;
    } else if (targetInfo.numbersBefore < 1 || entries > targetInfo.entries) {
      this.snackBar.open(
        'No es posible agregar conectores a ' +
          this.getNombreProceso(parseInt(targetInfo.process)),
        'Cerrar'
      );
      return false;
    }
    return true;
  }

  cambioProceso() {
    //¿El nodo seleccionado esta inicializado?
    if (Object.keys(this.nodoSeleccionado).length > 0) {
      //¿Existe el nodo en el diagrama?
      if (
        this.diagram!.selectedItems.nodes!.find(
          (node) => node.id == this.nodoSeleccionado.id
        )
      ) {
        //Seleccionar nodo del diagrama
        this.nodoSeleccionado = this.diagram!.selectedItems.nodes!.find(
          (node) => node.id == this.nodoSeleccionado.id
        ) as NodeModel;
        let nodeInfo = this.nodoSeleccionado.addInfo as NodeinfoInterface;

        //Asignar nuevo proceso
        nodeInfo.process = this.procesoSeleccionado;
        this.nodoSeleccionado.addInfo = nodeInfo;

        //¿El nodo tiene anotaciones?
        if (this.nodoSeleccionado.annotations!.length > 0) {
          //Se modifica su anotación
          this.nodoSeleccionado.annotations![0].content = this.getNombreProceso(
            parseInt(this.procesoSeleccionado)
          );
          //this.diagram.dataBind();
        } else {
          //Se registra una anotación
          this.diagram!.addNodeLabels(this.nodoSeleccionado, [
            {
              content: this.getNombreProceso(
                parseInt(this.procesoSeleccionado)
              ),
              style: { color: 'white' },
            },
          ]);
          //this.nodoSeleccionado = this.diagram.nodes.find(node => node.id == this.nodoSeleccionado.id) as NodeModel;
        }
      }
    }
  }

  cambioEmpleado() {
    //¿El nodo seleccionado esta inicializado?
    if (Object.keys(this.nodoSeleccionado).length > 0) {
      //¿Existe el nodo en el diagrama?
      if (
        this.diagram!.selectedItems.nodes!.some(
          (node) => node.id == this.nodoSeleccionado.id
        )
      ) {
        //Seleccionar nodo del diagrama
        this.nodoSeleccionado = this.diagram!.selectedItems.nodes!.find(
          (node) => node.id == this.nodoSeleccionado.id
        ) as NodeModel;
        let nodeInfo = this.nodoSeleccionado.addInfo as NodeinfoInterface;
        //Si el nodo no tenía empleados se permiten los tooltip
        if (nodeInfo.employee == '') {
          this.nodoSeleccionado.constraints =
            NodeConstraints.Default | NodeConstraints.Tooltip;
        }

        //Asignar nuevo empleado
        nodeInfo.employee = this.empleadoSeleccionado;
        this.nodoSeleccionado.addInfo = nodeInfo;

        //Modificar tooltip
        this.nodoSeleccionado.tooltip = {
          content: this.contentTooltip(nodeInfo),
          position: 'TopRight',
          relativeMode: 'Object',
        };
      }
    }
  }

  cambioNotificaciones() {
    //¿El nodo seleccionado esta inicializado?
    if (Object.keys(this.nodoSeleccionado).length > 0) {
      //¿Existe el nodo en el diagrama?
      if (
        this.diagram!.selectedItems.nodes!.some(
          (node) => node.id == this.nodoSeleccionado.id
        )
      ) {
        //Seleccionar nodo del diagrama
        this.nodoSeleccionado = this.diagram!.selectedItems.nodes!.find(
          (node) => node.id == this.nodoSeleccionado.id
        ) as NodeModel;
        let nodeInfo = this.nodoSeleccionado.addInfo as NodeinfoInterface;

        //Si el nodo no tenía notificaciones se permiten los tooltip
        if (!nodeInfo.notify) {
          this.nodoSeleccionado.constraints =
            NodeConstraints.Default | NodeConstraints.Tooltip;
        }

        //Asignar valor de notificaciones
        nodeInfo.notify = !nodeInfo.notify;
        this.nodoSeleccionado.addInfo = nodeInfo;

        //Modificar tooltip
        this.nodoSeleccionado.tooltip = {
          content: this.contentTooltip(nodeInfo),
          position: 'TopRight',
          relativeMode: 'Object',
        };
      }
    }
  }

  nodesDefault = (node: NodeModel) => {
    if (node.id == 'nota') {
      node.style = { fill: '#102027', strokeColor: 'white' };
      node.annotations = [
        {
          id: 'nota',
          width: 470,
          template: `
            <div class="nota" style="white-space: nowrap;">
              <p class="text-white text-hr">Reglas del diagrama: </p>
              <p class="text-white item-nota">I. Los conectores <span class="reglas-nodisponibles">rojos</span> no podrán ser modificados o eliminados.</p>
              <p class="text-white item-nota">II. Todos los conectores siempre deberán estar conectados al digrama.</p>
            </div>`,
        },
      ];
    } else {
      let nodeInfo = node.addInfo as any;

      node.style = { fill: '#37474f', strokeColor: 'white' };
      node.width = 130;
      node.height = 60;

      //El orden de los puertos esta basada en las manecillas del reloj
      //port1 = 12, port2 = 3, port3 = 6, port4 = 9
      node.ports = [
        { id: 'port1-node' + node.id, offset: { x: 0.5, y: 0 } },
        { id: 'port2-node' + node.id, offset: { x: 1, y: 0.5 } },
        { id: 'port3-node' + node.id, offset: { x: 0.5, y: 1 } },
        { id: 'port4-node' + node.id, offset: { x: 0, y: 0.5 } },
      ];

      if (!(nodeInfo.process == '')) {
        node.annotations = [
          {
            content: this.getNombreProceso(parseInt(nodeInfo.process)),
            style: {
              color: 'white',
            },
          },
        ];
      }

      if (!(nodeInfo.employee == '') || nodeInfo.notify) {
        node.tooltip = {
          content: this.contentTooltip(nodeInfo),
          position: 'TopRight',
          relativeMode: 'Object',
        };
      }
    }
  };

  getConnectorDefaults(obj: ConnectorModel) {
    if (obj.constraints == 470590) {
      obj.style = {
        strokeColor: '#004d40',
        fill: '#004d40',
        strokeWidth: 2,
      };
      obj.targetDecorator = {
        style: {
          fill: '#004d40',
          strokeColor: '#004d40',
        },
      };
    } else {
      obj.style = {
        strokeColor: '#EF2323',
        fill: '#EF2323',
        strokeWidth: 2,
      };

      obj.targetDecorator = {
        style: {
          fill: '#EF2323',
          strokeColor: '#EF2323',
        },
      };
    }
  }

  contentTooltip(nodeInfo: NodeinfoInterface): HTMLElement {
    let tooltipContent: HTMLElement = document.createElement('div');
    let colorNotification = nodeInfo.notify ? '#4c8c4a' : '#f44336';
    let typeNotification = nodeInfo.notify
      ? 'notifications_active'
      : 'notifications_off';

    if (!isNaN(parseInt(nodeInfo.employee))) {
      tooltipContent.innerHTML = `
      <div class="tooltip-employee">
        <span class="tooltip-flex">
          <span>${this.getNombreEmpleado(parseInt(nodeInfo.employee))}</span>
          <span class="material-icons" style="color: ${colorNotification}">${typeNotification}</span>
        </span> 
      </div>`;
    } else {
      tooltipContent.innerHTML = `
      <div class="tooltip-notification">
        <span class="tooltip-flex">
          <span class="material-icons" style="color: ${colorNotification}">${typeNotification}</span>
        </span> 
      </div>`;
    }

    return tooltipContent;
  }

  created() {
    const connectors = this.diagram!.connectors;
    const connectors_map = connectors.map((connector) => {
      return { source: connector.sourceID, target: connector.targetID };
    });
    this.conectores_base = connectors_map;
    this.zoomOut();
  }

  getDiagram() {
    this.isSecuencia = false;
  }

  //Obtener nombre del proceso apartir de su id
  getNombreProceso(id: number): string {
    const index = this.procesos.findIndex((proceso) => proceso.id === id);

    if (index == -1) {
      return '';
    }

    return this.procesos[index].name;
  }

  //Agregar componente al diagrama
  getNombreEmpleado(id: number): string {
    const index = this.empleados.findIndex((empleado) => empleado.id === id);

    if (index == -1) {
      return '';
    }

    return this.empleados[index].name;
  }

  //Agregar secuencia al diagrama
  getNumeroSecuencia(nombre: string): number {
    const secuencias = [
      { secuencia: 1, nombre: 'Validar 1' },
      { secuencia: 2, nombre: 'Aprobar solicitud 7' },
      { secuencia: 3, nombre: 'Rechazado 8' },
      { secuencia: 4, nombre: 'Pendiente de aprobación 9' },
      { secuencia: 5, nombre: 'Aprobado 15' },
    ];

    const index = secuencias.findIndex(
      (secuencia) => secuencia.nombre === nombre
    );

    if (index == -1) {
      return -1;
    }
    return secuencias[index].secuencia;
  }

  getSymbolInfo(symbol: any) {
    return { fit: true };
  }

  /*getBasicShapes(): NodeModel[] {
    let basicShapes: NodeModel[] = [
      {
        id: 'Rectangle',
        shape: {
          type: 'Basic',
          shape: 'Rectangle',
        },
      },
      {
        id: 'Ellipse',
        shape: {
          type: 'Basic',
          shape: 'Ellipse',
        },
      },
    ];
    return basicShapes;
  }*/

  getFlowShapes(): NodeModel[] {
    let flowShapes: NodeModel[] = [
      {
        id: 'data',
        shape: {
          type: 'Flow',
          shape: 'Data',
        },
      },
      {
        id: 'process',
        shape: {
          type: 'Flow',
          shape: 'Process',
        },
      },
      {
        id: 'decision',
        shape: {
          type: 'Flow',
          shape: 'Decision',
        },
      },
    ];
    return flowShapes;
  }

  getConnectors(): ConnectorModel[] {
    let connectorSymbols: ConnectorModel[] = [
      {
        id: 'Link1',
        type: 'Orthogonal',
        sourcePoint: {
          x: 0,
          y: 0,
        },
        targetPoint: {
          x: 40,
          y: 40,
        },
        targetDecorator: {
          shape: 'Arrow',
          style: {
            strokeWidth: 2,
            strokeColor: 'white',
          },
        },
        style: {
          strokeWidth: 2,
          strokeColor: 'white',
        },
      },
      {
        id: 'Link21',
        type: 'Straight',
        sourcePoint: {
          x: 0,
          y: 0,
        },
        targetPoint: {
          x: 40,
          y: 40,
        },
        targetDecorator: {
          shape: 'Arrow',
          style: {
            strokeWidth: 2,
            strokeColor: 'white',
          },
        },
        style: {
          strokeWidth: 2,
          strokeColor: 'white',
        },
      },
    ];
    return connectorSymbols;
  }

  zoomIn() {
    let zoomOptions: ZoomOptions = {
      type: 'ZoomIn',
      //Sets the factor by which we can zoom in or zoom out
      zoomFactor: 0.5,
    };
    //zoomin the diagram
    this.diagram!.zoomTo(zoomOptions);
  }

  zoomOut() {
    let zoomOptions: ZoomOptions = {
      type: 'ZoomOut',
      zoomFactor: 0.1,
    };
    this.diagram!.zoomTo(zoomOptions);
  }

  onResize(event: any) {
    this.pantallaGrande = event.target.innerWidth > 1700;
  }
}
