import { Component, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ElementRef, ViewEncapsulation } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { tap, take, map, catchError, switchMap, filter, shareReplay, retry } from 'rxjs/operators';
import { of, BehaviorSubject, Subject } from 'rxjs';
import { State } from '@progress/kendo-data-query';
import { PathingService, Detail, Item, RequiredData, SaveType, MeterItem, TransferMeterMapItem, PathRouteItem, } from './pathing.service';
import { MessageService } from '../../_shared/services/message.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { DialogService, DialogSettings } from '@progress/kendo-angular-dialog';
import { NotifyService } from '../../_shared/services/notify.service';
import { TooltipDirective } from '@progress/kendo-angular-tooltip';
import * as util from '../../_shared/utils/util';
import { CellClickEvent, SelectableSettings } from '@progress/kendo-angular-grid';
import { PathContract } from './pathing.service';
import { FAST_KENDO_COMMON, FAST_PAGE_COMMON } from '../../app.config';

@Component({
  /*
  The ":not(p)" in the selector is to prevent a component ID collision
  with the gas version of app-pathing.  It has no other effect.

  For more details, see:  https://angular.dev/errors/NG0912
  */
  selector: 'app-pathing:not(p)',
  templateUrl: './pathing.component.html',
  styleUrls: ['./pathing.component.scss'],
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [FAST_PAGE_COMMON, FAST_KENDO_COMMON]
})
export class PathingComponent {
  @ViewChild("grid", { read: ElementRef }) kendoGridEl: ElementRef;
  @ViewChild('tooltipGrid') tooltipGrid: TooltipDirective;

  icons = util.icons;
  gridScrollTopPos: number;
  gridScrollLeftPos: number;
  mySelection: number[] = [];
  formEditor: FormGroup;
  hasModifyPermission = false;
  localRequiredData: RequiredData;
  selectedSegmentRowNum: number = 0;
  segmentCount: number = 0;
  subToContracts: PathContract[] = [];
  //lists for Source CounterParty, Source Pipe, Source Meter, Source Contract
  listCounterparties: util.IdName[] = [];
  listContracts: PathContract[] = [];
  listPipes: util.IdName[] = [];
  listMeters: MeterItem[] = [];
  //lists for subFromPipes, To Pipe, Interconnect Meter, To Contract
  subItems: util.IdName[] = [];
  subContracts: PathContract[] = [];
  subPipes: util.IdName[] = [];
  subMeters: MeterItem[] = [];
  subFromPipes: util.IdName[] = [];
  subInterconnectMeters: TransferMeterMapItem[] = [];
  //all lists that was coming from API
  allItems: util.IdName[] = [];
  allContracts: PathContract[] = [];
  allPipes: util.IdName[] = [];
  allMeters: MeterItem[] = [];
  detailGridSelection: object[] = [];

  sourceContractId: number;
  sourceSubContractId: number;
  selectedFromRoute: PathRouteItem = null;
  selectedToRoute: PathRouteItem = null;
  nextFromRoute: PathRouteItem = null;
  nextToRoute: PathRouteItem = null;
  addSegmentDisabled = false;

  gridData: PathRouteItem[];
  selectableSettings: SelectableSettings = {
    checkboxOnly: false,
    mode: 'single',
    enabled: true
  }

  exporting$ = new BehaviorSubject<boolean>(false)
  editorOpened$ = new BehaviorSubject<boolean>(false)
  loading$ = new BehaviorSubject<boolean>(true);
  gridLoading$ = new BehaviorSubject<boolean>(true)
  editorLoading$ = new BehaviorSubject<boolean>(true);

  state: State = {
    filter: null,
    group: null,
    skip: 0,
    sort: [{ field: 'PathName', dir: 'asc' }],
    take: 100
  };

  constructor(private messageService: MessageService, private titleService: Title, private service: PathingService, private fb: FormBuilder, private ref: ChangeDetectorRef, private dialogService: DialogService, private notify: NotifyService) {
    this.formEditor = fb.group({
      pathId: [0, Validators.required],
      pathName: [null, Validators.required],
      sourceCounterpartyId: [null, Validators.required],
      sourceMeterId: [null, Validators.required],
      sourceSubMeterId: [null],
      sourcePipeId: [null],
      sourceSubPipeId: [null],
      sourceFromPipeId: [null],
      sourceContractId: [null, Validators.required],
      sourceSubContractId: [null],
      pathRoutes: [[]],

    });
    this.formEditor.disable();
  }

  exportClicked$ = new Subject()

  refreshItems$ = new BehaviorSubject<string>(null)
  refreshDetail$ = new BehaviorSubject<number>(null)
  refreshRequiredData$ = new BehaviorSubject(null)

  save$ = new Subject<SaveType>()
  delete$ = new Subject()

  title$ = of('SOS Pathing').pipe(
    tap((title) => util.trySetTitle(this.titleService, title))
  )

  getMaxWindowHeight() {
    return window.innerHeight;
  }

  getMaxWindowWidth() {
    return window.innerWidth;
  }

  requiredData$ = this.refreshRequiredData$.pipe(
    switchMap(() => {
      return this.service.requiredData$;
    }),
    map(requiredData => {
      this.localRequiredData = requiredData;
      this.listCounterparties = requiredData.counterparties;
      this.listContracts = requiredData.contracts;
      this.listMeters = requiredData.meters;
      this.listPipes = requiredData.pipelines;

      this.subContracts = requiredData.contracts;
      this.subItems = requiredData.counterparties;
      this.subMeters = requiredData.meters;
      this.subPipes = requiredData.pipelines;
      this.subFromPipes = requiredData.pipelines;

      this.allContracts = requiredData.contracts;
      this.allItems = requiredData.counterparties;
      this.allMeters = requiredData.meters;
      this.allPipes = requiredData.pipelines;

      return requiredData;
    }),
    tap((requiredData) => {
      this.hasModifyPermission = requiredData.hasModifyPermission;
      this.loading$.next(false);
      util.focusInputTarget()
    }),
    shareReplay(1),
    catchError(err => {
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  items$ = this.refreshItems$.pipe(
    tap(() => {
      this.gridLoading$.next(true);
    }),
    switchMap(() => {
      return this.service.getItems(this.state);
    }),
    tap(() => {
      this.gridLoading$.next(false);
      this.goToSavedGridScrollPos();
    }),
    shareReplay(1),
    catchError(err => {
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  exportAction$ = this.exportClicked$.pipe(
    switchMap(() => {
      this.exporting$.next(true);
      return this.service.exportItems(this.state, 'Pathing.xlsx');
    }),
    tap(res => {
      util.openOrSaveFile(res.fileBlob, res.fileName);
      this.exporting$.next(false);
    }),
    shareReplay(1),
    catchError(err => {
      this.exporting$.next(false);
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  getNewDetail(): Detail {
    const item: Detail = {
      pathId: 0,
      pathName: null,
      sourceContractId: null,
      sourceCounterpartyId: null,
      sourceMeterId: null,
      sourcePipeId: null,
      sourceSubMeterId: null,
      sourceSubPipeId: null,
      sourceFromPipeId: null,
      sourceSubContractId: null,
      pathRoutes: []
    };
    return item;
  }

  detail$ = this.refreshDetail$.pipe(
    filter(id => id !== null),
    switchMap(id => {
      if (id === 0)
        return of(this.getNewDetail());
      else
        return this.service.getDetail(id);
    }),
    map(result => {
      const detail: Detail = result;
      this.setEditorItem(detail);
      return detail;
    }),
    tap(() => {
      this.editorFinishedLoading();
      this.setSourcePipeState();
      this.refreshObservables();
    }),
    shareReplay(1),
    catchError(err => {
      this.closeEditor(false);
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  saveResult$ = this.save$.pipe(
    switchMap(saveType => {
      const itemToSave: Detail = this.formEditor.getRawValue();
      this.formEditor.disable();
      return this.service.saveDetail(itemToSave, saveType);
    }),
    tap((saveResult) => {
      this.notify.success('save successful');
      this.closeEditor(false);
      this.refreshItems$.next(null);
      this.mySelection = [saveResult];
    }),
    shareReplay(1),
    catchError(err => {
      this.editorFinishedLoading();
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  deleteResult$ = this.delete$.pipe(
    switchMap(() => {
      const itemToDelete: Detail = this.formEditor.getRawValue();
      return this.service.deleteDetail(itemToDelete.pathId);
    }),
    tap(() => {
      this.notify.success('delete successful');
      this.editorFinishedLoading();
      this.closeEditor(false);
      this.refreshItems$.next(null);
    }),
    shareReplay(1),
    catchError(err => {
      this.editorLoading$.next(false);
      this.formEditor.enable();
      return util.handleError(err, this.messageService)
    }), retry(10)
  )

  setEditorItem(editorItem: Detail): void {
    //use setTimeout since the form controls may not be registered yet
    setTimeout(() => {
      this.listMeters = this.allMeters.filter(s => s.pipeId == editorItem.sourcePipeId);
      this.refreshListMeters$.next(null);
      this.formEditor.setValue(editorItem);
      this.gridData = editorItem.pathRoutes;
      this.segmentCount = this.gridData.length;
      this.setSelectedSegmentRoutes();
      if (this.selectedFromRoute?.pipeId)
        this.formEditor.controls['sourceFromPipeId'].setValue(this.selectedFromRoute.pipeId);
      this.subInterconnectMeters = [];
      this.refreshListSubInterconnectMeters$.next(null);
    });
  }

  openEditor(id: number): void {
    this.selectedSegmentRowNum = 0;
    this.tooltipGrid.hide();
    this.formEditor.disable();
    this.editorLoading$.next(true);
    this.saveGridScrollPos();
    this.formEditor.reset();
    this.editorOpened$.next(true);
    this.refreshDetail$.next(id);
  }

  closeEditor = (isFromInterface: boolean) => {
    this.editorFinishedLoading();

    if (!isFromInterface) {
      this.editorFinishedLoading();
      this.editorOpened$.next(false);
    }
    else {
      this.editorFinishedLoading();
      this.editorOpened$.next(false);
      setTimeout(() => {
        this.goToSavedGridScrollPos();
      }, 100);
    }
  }

  editorFinishedLoading(): void {
    this.editorLoading$.next(false);
    if (this.formEditor.disabled)
      this.formEditor.enable();
    this.formEditor.controls['sourceFromPipeId'].disable();
    util.focusInputTarget();
  }

  add(): void {
    if (this.hasModifyPermission) {
      this.openEditor(0);
      this.editorFinishedLoading();
    }
  }

  edit(dataItem: Item): void {
    this.openEditor(dataItem.PathId);
  }

  save(): void {
    this.formEditor.markAllAsTouched();
    if (this.formEditor.valid) {
      this.editorLoading$.next(true);
      const saveType = this.formEditor.get('pathId').value === 0 ? SaveType.New : SaveType.Normal;
      this.save$.next(saveType);
    } else {
      this.notify.error("validation failed");
    }
  }

  delete(): void {
    const deleteConfirmSettings: DialogSettings = {
      title: "Please confirm",
      content: "Are you sure you want to delete this item?",
      actions: [{ text: 'No' }, { text: 'Yes', cssClass: 'k-primary' }],
      cssClass: 'utilPrompt'
    }

    this.dialogService.open(deleteConfirmSettings).result.pipe(take(1)).subscribe(result => {
      if (util.getDialogAction(result) === util.dialogAction.Yes) {
        this.formEditor.disable();
        this.editorLoading$.next(true);
        this.delete$.next(null);
      }
    });
  }

  export(): void {
    this.exportClicked$.next(null);
  }

  getGridContentElement(): Element {
    const el = this.kendoGridEl?.nativeElement as HTMLElement;
    const gridContent = el?.getElementsByClassName("k-grid-content").item(0);
    return gridContent;
  }

  saveGridScrollPos(): void {
    const gridContent = this.getGridContentElement();
    this.gridScrollTopPos = gridContent ? gridContent.scrollTop : 0;
    this.gridScrollLeftPos = gridContent ? gridContent.scrollLeft : 0;
  }

  goToSavedGridScrollPos(): void {
    setTimeout(() => {
      const gridContent = this.getGridContentElement();
      if (gridContent)
        gridContent.scrollTo({ top: this.gridScrollTopPos, left: this.gridScrollLeftPos });
    });
  }

  dataStateChange(state: State): void {
    this.gridScrollTopPos = 0;
    this.gridScrollLeftPos = 0;
    util.fixKendoQueryFilter(state.filter);
    this.state = state;
    this.refreshItems$.next(null);
  }

  onEditorClosed() {
    if (this.formEditor.dirty) {
      const unsavedChangesSettings: DialogSettings = {
        title: "Please confirm",
        content: "You have unsaved changes. What would you like to do?",
        actions: [{ text: 'Save', cssClass: 'k-primary' }, { text: 'Don\'t Save' }, { text: 'Cancel' }],
        cssClass: 'utilPrompt'
      }

      this.dialogService.open(unsavedChangesSettings).result.pipe(take(1)).subscribe(result => {
        if (util.getDialogAction(result) === util.dialogAction.Save)
          this.save();
        else if (util.getDialogAction(result) === util.dialogAction.DontSave)
          this.closeEditor(true);
      });
    } else
      this.closeEditor(true);
  }

  showGridTooltip(e: MouseEvent): void {
    const element = e.target as HTMLElement;
    if ((element.nodeName === 'TD' || element.nodeName === 'TH') && util.isClipped(element, 12)) {
      this.tooltipGrid.showOn = "hover";
      this.tooltipGrid.toggle(element);
    }
    else {
      this.tooltipGrid.showOn = "none";
      this.tooltipGrid.hide();
    }
  }

  removeSegment() {
    const item: Detail = this.formEditor.getRawValue();
    if (item?.pathRoutes && item.pathRoutes.length > 3) {
      item.pathRoutes = item.pathRoutes.slice(0, item.pathRoutes.length - 2);
      this.formEditor.controls['pathRoutes'].setValue(item.pathRoutes);
    }
    else {
      item.pathRoutes = [];
      this.formEditor.controls['pathRoutes'].setValue([]);
    }
    this.gridData = item.pathRoutes;
    this.updateSegmentCount();
    this.clearSelection();
    this.setSourcePipeState();
  }

  updateSegmentCount() {
    const item: Detail = this.formEditor.getRawValue();
    if (item?.pathRoutes)
      this.segmentCount = item.pathRoutes.length;
    else
      this.segmentCount = 0;
  }

  addSegment() {
    let pipeName: string;
    let meter: MeterItem;
    let interconnectMeter: TransferMeterMapItem;
    let contract: PathContract;
    let segment: PathRouteItem;
    let isFirstSegment = false;
    const item: Detail = this.formEditor.getRawValue();
    if (item?.pathRoutes && item.pathRoutes.length === 0)
      isFirstSegment = true;

    if (!isFirstSegment) {
      //isFirstSegment = false
      //contract for the first piece is the same as the previous segment's last piece
      const prevContractId = item.pathRoutes[item.pathRoutes.length - 1].contractId;
      contract = this.allContracts.find(s => s.contractId == prevContractId);;
    }
    else {
      contract = this.allContracts.find(s => s.contractId == item.sourceContractId);
      meter = this.allMeters.find(m => m.meterId == item.sourceMeterId);
      pipeName = this.allPipes.find(p => p.id == item.sourcePipeId).name;
      segment = {
        pipeId: meter ? meter.pipeId : null,
        pipeName: pipeName,
        meterName: meter ? meter.meterName : null,
        contractId: contract.contractId,
        contractNum: contract ? contract.contractNum : null,
        contractOwner: contract ? contract.contractOwner : null,
        meterMapId: 0,
        isMeter1First: false
      };
      item.pathRoutes.push(segment);
    }

    interconnectMeter = this.subInterconnectMeters.find(sm => sm.transferMeterMapId == item.sourceSubMeterId);
    meter = this.allMeters.find(m => m.meterId == ((interconnectMeter.isMeter1First) ? interconnectMeter.meter1Id : interconnectMeter.meter2Id));
    pipeName = this.allPipes.find(p => p.id == meter.pipeId).name;
    segment = {
      pipeId: meter ? meter.pipeId : null,
      pipeName: pipeName,
      meterName: meter ? meter.meterName : null,
      contractId: contract.contractId,
      contractNum: contract ? contract.contractNum : null,
      contractOwner: contract ? contract.contractOwner : null,
      meterMapId: interconnectMeter.transferMeterMapId,
      isMeter1First: interconnectMeter.isMeter1First
    };
    item.pathRoutes.push(segment);
    contract = this.allContracts.find(s => s.contractId == item.sourceSubContractId);
    interconnectMeter = this.subInterconnectMeters.find(sm => sm.transferMeterMapId == item.sourceSubMeterId);
    meter = this.allMeters.find(m => m.meterId == ((interconnectMeter.isMeter1First) ? interconnectMeter.meter2Id : interconnectMeter.meter1Id));
    pipeName = this.allPipes.find(p => p.id == meter.pipeId).name;
    segment = {
      pipeId: meter ? meter.pipeId : null,
      pipeName: pipeName,
      meterName: meter ? meter.meterName : null,
      contractId: contract.contractId,
      contractNum: contract ? contract.contractNum : null,
      contractOwner: contract ? contract.contractOwner : null,
      meterMapId: interconnectMeter.transferMeterMapId,
      isMeter1First: interconnectMeter.isMeter1First
    };
    item.pathRoutes.push(segment);
    this.gridData = item.pathRoutes;
    this.setSelectedSegmentValues();
    this.setSourcePipeState();
  }

  sourcePipeChanged() {
    const item: Detail = this.formEditor.getRawValue();
    this.listMeters = this.allMeters.filter(s => s.pipeId == item.sourcePipeId);
    this.refreshListMeters$.next(null);
    this.formEditor.controls['sourceMeterId'].setValue(null);
    if (this.listMeters.length === 1)
      this.formEditor.controls['sourceMeterId'].setValue(this.listMeters[0].meterId);
    this.updateSourceContracts();
    this.formEditor.controls['sourceSubPipeId'].setValue(null);
    this.formEditor.controls['sourceSubMeterId'].setValue(null);
    this.formEditor.controls['sourceSubContractId'].setValue(null);
    this.toPipeChanged();
  }

  updateSourceContracts() {
    const item: Detail = this.formEditor.getRawValue();
    if (item?.sourcePipeId) {
      this.listContracts = this.allContracts.filter(s => s.contractPipeId == item.sourcePipeId);
      this.refreshListContracts$.next(null);
      this.formEditor.controls['sourceContractId'].setValue(null);
      if (this.listContracts.length === 1)
        this.formEditor.controls['sourceContractId'].setValue(this.listContracts[0].contractId);
      this.sourceContractChanged();
    }
  }

  sourceContractChanged() {
    const item: Detail = this.formEditor.getRawValue();
    if (item?.pathRoutes && item.pathRoutes.length > 0 && item.sourceContractId) {
      const firstSegment = item.pathRoutes[0];
      const contractId = item.sourceContractId ? item.sourceContractId : null;
      const contract = this.allContracts.find(s => s.contractId == contractId);
      firstSegment.contractId = contractId;
      firstSegment.contractNum = contract.contractNum;
      firstSegment.contractOwner = contract.contractOwner;

      const secondSegment = item.pathRoutes[1];
      secondSegment.contractId = contractId;
      secondSegment.contractNum = contract.contractNum;
      secondSegment.contractOwner = contract.contractOwner;

      this.gridData = item.pathRoutes;
    }
  }

  toPipeChanged() {
    this.updateSubInterconnectMeters();
    this.updateToContracts();
  }

  selectRow(selectedPathRoute: CellClickEvent) {
    this.selectedSegmentRowNum = this.getSegmentRowNum(selectedPathRoute.dataItem);
    this.setSelectedSegmentValues();
  }

  setSelectedSegmentValues() {
    this.setToPipeState();
    this.setSelectedSegmentRoutes();
    this.setSelectedSegmentPipes();
  }

  setSelectedSegmentRoutes() {
    this.selectedFromRoute = null;
    this.selectedToRoute = null;
    this.nextFromRoute = null;
    this.nextToRoute = null;
    const item: Detail = this.formEditor.getRawValue();

    if (item?.pathRoutes && item.pathRoutes.length > 0) {
      if (this.selectedSegmentRowNum === 1) {  //first row selected
        this.selectedFromRoute = item.pathRoutes[1]; // this is second row since path is 0 based
        this.selectedToRoute = item.pathRoutes[2]; // this is third row since path is 0 based

        const hasNextRoute = this.segmentCount > 3;
        if (hasNextRoute) {
          this.nextFromRoute = item.pathRoutes[3];
          this.nextToRoute = item.pathRoutes[4];
        }
      }
      else if (this.selectedSegmentRowNum >= 2) { //second or great row selected
        const fromRouteNum = this.selectedSegmentRowNum % 2 === 0 ? this.selectedSegmentRowNum : this.selectedSegmentRowNum - 1;
        this.selectedFromRoute = item.pathRoutes[fromRouteNum - 1]; // -1 since pathRoutes is 0 based
        const toRouteNum = fromRouteNum + 1;
        this.selectedToRoute = item.pathRoutes[toRouteNum - 1]; // -1 since pathRoutes is 0 based

        const hasNextRoute = this.segmentCount > toRouteNum;
        if (hasNextRoute) {
          this.nextFromRoute = item.pathRoutes[toRouteNum + 1 - 1];
          this.nextToRoute = item.pathRoutes[toRouteNum + 2 - 1];
        }
      } else if (this.selectedSegmentRowNum === 0) { //no row selected
        const fromRouteNum = item.pathRoutes.length;
        this.selectedFromRoute = item.pathRoutes[fromRouteNum - 1]; // -1 since pathRoutes is 0 based
      }
    }
  }

  setSelectedSegmentPipes() {
    if (this.selectedFromRoute && this.selectedToRoute) {
      this.formEditor.controls['sourceFromPipeId'].setValue(this.selectedFromRoute.pipeId);
      this.formEditor.controls['sourceSubPipeId'].setValue(this.selectedToRoute.pipeId);
    }
    else if (this.selectedFromRoute) {
      this.formEditor.controls['sourceFromPipeId'].setValue(this.selectedFromRoute.pipeId);
      this.formEditor.controls['sourceSubPipeId'].setValue(null);
    }
    this.toPipeChanged();
  }

  getSegmentRowNum(item: PathRouteItem) {
    const segmentGridItems = this.gridData;
    for (let i = 0; i < segmentGridItems.length; i++) {
      if (segmentGridItems[i] === item)
        return i + 1;
    }
    return 0;
  }

  isAddSegmentDisabled() {
    const item: Detail = this.formEditor.getRawValue();
    return !item || !item.sourcePipeId || !item.sourceSubPipeId || !item.sourceSubMeterId || this.selectedSegmentRowNum > 0;
  };

  isRemoveSegmentDisabled() {
    const item: Detail = this.formEditor.getRawValue();
    if (item?.pathRoutes === null)
      this.formEditor.controls['pathRoutes'].setValue([]);
    return !item?.pathRoutes || item.pathRoutes.length === 0;
  };

  setSourcePipeState() {
    setTimeout(() => {
      const item: Detail = this.formEditor.getRawValue();
      if (item?.pathRoutes?.length > 0)
        this.formEditor.controls['sourcePipeId'].disable();
      else
        this.formEditor.controls['sourcePipeId'].enable();
    });
  };

  setToPipeState() {
    const item: Detail = this.formEditor.getRawValue();
    if (!item || this.selectedSegmentRowNum > 0)
      this.formEditor.controls['sourceSubPipeId'].disable();
    else
      this.formEditor.controls['sourceSubPipeId'].enable();
  }

  isClearDisabled() {
    return this.selectedSegmentRowNum === 0;
  }

  updateSubInterconnectMeters() {
    let fromPipeId;
    const item: Detail = this.formEditor.getRawValue();

    if (item?.pathRoutes && item.pathRoutes.length === 0) //no segments
      fromPipeId = item.sourcePipeId ? item.sourcePipeId : null;
    else if (this.selectedSegmentRowNum === 0) //segments exist but no row selected
    {
      const pId = item.pathRoutes[item.pathRoutes.length - 1].pipeId;
      fromPipeId = pId ? pId : null;
    }
    else if (this.selectedSegmentRowNum > 0 && this.selectedSegmentRowNum <= 3) //first segment group selected
      fromPipeId = item.sourcePipeId ? item.sourcePipeId : null;
    else if (this.selectedSegmentRowNum >= 4) //second or later segment group selected
      fromPipeId = item.sourceFromPipeId ? item.sourceFromPipeId : null;

    const toPipeId = item.sourceSubPipeId ? item.sourceSubPipeId : null;
    if (fromPipeId && toPipeId) {
      this.editorLoading$.next(true);
      this.service.getTransferMeterMaps(fromPipeId, toPipeId).subscribe(result => {
        this.editorLoading$.next(false);
        this.subInterconnectMeters = result;
        this.refreshListSubInterconnectMeters$.next(null);
        this.setSelectedSegmentMeter();
      })
    }
    else {
      this.subInterconnectMeters = [];
      this.refreshListSubInterconnectMeters$.next(null);
      this.formEditor.controls['sourceSubMeterId'].setValue(null);
    }
  }

  updateToContracts() {
    const item: Detail = this.formEditor.getRawValue();
    if (item?.sourceSubPipeId) {
      this.subToContracts = this.allContracts.filter(x => x.contractPipeId == item.sourceSubPipeId);
      this.subContracts = this.subToContracts;
      this.refreshListSubContracts$.next(null);
      this.setSelectedSegmentContract();
    } else {
      this.subContracts = [];
      this.refreshListSubContracts$.next(null);
      this.formEditor.controls['sourceSubContractId'].setValue(null);
    }
  }

  setSelectedSegmentContract() {
    const item: Detail = this.formEditor.getRawValue();
    this.formEditor.controls['sourceSubContractId'].setValue(null);

    if (this.selectedFromRoute && this.selectedToRoute)
      this.formEditor.controls['sourceSubContractId'].setValue(this.selectedToRoute.contractId ? this.selectedToRoute.contractId : null);

    if (item?.sourceSubContractId === null && this.subToContracts.length === 1)
      this.formEditor.controls['sourceSubContractId'].setValue(this.subToContracts[0].contractId);
  }

  setSelectedSegmentMeter() {
    const item: Detail = this.formEditor.getRawValue();
    this.formEditor.controls['sourceSubMeterId'].setValue(null);

    if (this.selectedFromRoute && this.selectedToRoute)
      this.formEditor.controls['sourceSubMeterId'].setValue(this.selectedToRoute.meterMapId ? this.selectedToRoute.meterMapId : null);

    if (item?.sourceSubMeterId === null && this.subInterconnectMeters.length === 1)
      this.formEditor.controls['sourceSubMeterId'].setValue(this.subInterconnectMeters[0].transferMeterMapId);
  }

  clearSelection() {
    this.selectedSegmentRowNum = 0;
    this.setSelectedSegmentValues();
    this.detailGridSelection = [];
  }

  refreshObservables() {
    this.refreshListCounterparties$.next(null);
    this.refreshListPipes$.next(null);
    this.refreshListMeters$.next(null);
    this.refreshListContracts$.next(null);
    this.refreshListSubFromPipes$.next(null);
    this.refreshListSubPipes$.next(null);
    this.refreshListSubInterconnectMeters$.next(null);
    this.refreshListSubContracts$.next(null);
  }

  refreshListCounterparties$ = new BehaviorSubject<string>(null)
  listCounterparties$ = this.refreshListCounterparties$.pipe(map(() => this.listCounterparties));
  filterCounterparties$ = new BehaviorSubject<string>(null)
  counterparties$ = this.filterCounterparties$.pipe(util.filterIdNames(of(false), this.listCounterparties$, null));

  refreshListPipes$ = new BehaviorSubject<string>(null)
  listPipes$ = this.refreshListPipes$.pipe(map(() => this.listPipes));
  filterPipelines$ = new BehaviorSubject<string>(null)
  pipelines$ = this.filterPipelines$.pipe(util.filterIdNames(of(false), this.listPipes$, null));

  refreshListMeters$ = new BehaviorSubject<string>(null)
  listMeters$ = this.refreshListMeters$.pipe(map(() => this.listMeters));
  filterMeters$ = new BehaviorSubject<string>(null)
  meters$ = this.filterMeters$.pipe(util.filterSpecials(of(false), this.listMeters$, null, 'meterName'));

  refreshListContracts$ = new BehaviorSubject<string>(null)
  listContracts$ = this.refreshListContracts$.pipe(map(() => this.listContracts));
  filterContracts$ = new BehaviorSubject<string>(null)
  contracts$ = this.filterContracts$.pipe(util.filterSpecials(of(false), this.listContracts$, null, 'contractNum'));

  refreshListSubFromPipes$ = new BehaviorSubject<string>(null)
  listSubFromPipes$ = this.refreshListSubFromPipes$.pipe(map(() => this.subFromPipes));
  filterSubFromPipes$ = new BehaviorSubject<string>(null)
  subFromPipes$ = this.filterSubFromPipes$.pipe(util.filterIdNames(of(false), this.listSubFromPipes$, null));

  refreshListSubPipes$ = new BehaviorSubject<string>(null)
  listSubPipes$ = this.refreshListSubPipes$.pipe(map(() => this.subPipes));
  filterSubPipes$ = new BehaviorSubject<string>(null)
  subPipes$ = this.filterSubPipes$.pipe(util.filterIdNames(of(false), this.listSubPipes$, null));

  refreshListSubInterconnectMeters$ = new BehaviorSubject<string>(null)
  listSubInterconnectMeters$ = this.refreshListSubInterconnectMeters$.pipe(map(() => this.subInterconnectMeters));
  filterSubInterconnectMeters$ = new BehaviorSubject<string>(null)
  subInterconnectMeters$ = this.filterSubInterconnectMeters$.pipe(util.filterSpecials(of(false), this.listSubInterconnectMeters$, null, 'transferMeterMapName'));

  refreshListSubContracts$ = new BehaviorSubject<string>(null)
  listSubContracts$ = this.refreshListSubContracts$.pipe(map(() => this.subContracts));
  filterSubContracts$ = new BehaviorSubject<string>(null)
  subContracts$ = this.filterSubContracts$.pipe(util.filterSpecials(of(false), this.listSubContracts$, null, 'contractDesc'));
}
