//  Copyright (c) 2024 Huawei Technologies Co., Ltd.
//  openUBMC is licensed under Mulan PSL v2.
//  You can use this software according to the terms and conditions of the Mulan PSL v2.
//  You may obtain a copy of Mulan PSL v2 at:
//        #  http://license.coscl.org.cn/MulanPSL2
//  THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
//  EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
//  MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
//  See the Mulan PSL v2 for more details.
import { stringToBytes1 } from '../utils/kvm-h5.util';
import { UniqueIdDisposer } from './uniqueIdDisposer';
import { FileEntryPositions } from './fileEntryPositions';
export class UdfLayoutInformation {
  public myUniqueIdDisposer: any;

  public blockSize: number = 0;

  public metadataAllocationUnitSize: number = 0;
  public metadataAlignmentUnitSize: number = 0;

  public fileCount: number = 0;
  public directoryCount: number = 0;

  public avdp1Block: number = 0;
  public avdp2Block: number = 0;

  public mvdsStartingBlock: number = 0;
  public mvdsEndingBlock: number = 0;

  public rvdsStartingBlock: number = 0;
  public rvdsEndingBlock: number = 0;

  public lvidsStartingBlock: number = 0;
  public lvidsEndingBlock: number = 0;

  public physicalPartitionStartingBlock: number = 0;
  public physicalPartitionEndingBlock: number = 0;

  public metadataPartitionStartingBlock: number = 0;
  public metadataPartitionEndingBlock: number = 0;

  public mainMetadataFileBlock: number = 0;
  public mainMetadataFileLocation: number = 0;

  public mirrorMetadataFileBlock: number = 0;
  public mirrorMetadataFileLocation: number = 0;

  public metadataEmptyArea: any;

  public partitionToStoreMetadataOn: number = 0;

  public fsdBlock: number = 0;
  public fsdLocation: number = 0;

  public rootFEBlock: number = 0;
  public rootFELocation: number = 0;

  public pvd1Block: number = 0;
  public pvd2Block: number = 0;
  public pd1Block: number = 0;
  public pd2Block: number = 0;
  public lvd1Block: number = 0;
  public lvd2Block: number = 0;
  public usd1Block: number = 0;
  public usd2Block: number = 0;
  public iuvd1Block: number = 0;
  public iuvd2Block: number = 0;
  public td1Block: number = 0;
  public td2Block: number = 0;

  public sizeTable: any;
  public freespaceTable: any;

  public nextUniqueId: any;

  public linearUDFImageBuilderFileOrdering: any;

  public fileEntryPositions: any;

  init(rootUDFImageBuilderFile: any, myUDFRevision: any, blockSize: number) {
    this.myUniqueIdDisposer = new UniqueIdDisposer();

    this.fileEntryPositions = [];
    this.linearUDFImageBuilderFileOrdering = [];

    this.blockSize = blockSize;
    this.metadataAllocationUnitSize = 32;
    this.metadataAlignmentUnitSize = 1;

    this.fileCount = rootUDFImageBuilderFile.getFileCount();
    this.directoryCount = rootUDFImageBuilderFile.getDirectoryCount();

    this.avdp1Block = 256;

    this.mvdsStartingBlock = 257;
    this.mvdsEndingBlock = this.mvdsStartingBlock + 16;
    this.pvd1Block = this.mvdsStartingBlock;
    this.pd1Block = this.mvdsStartingBlock + 1;
    this.lvd1Block = this.mvdsStartingBlock + 2;
    this.usd1Block = this.mvdsStartingBlock + 3;
    this.iuvd1Block = this.mvdsStartingBlock + 4;
    this.td1Block = this.mvdsStartingBlock + 5;

    this.lvidsStartingBlock = this.mvdsEndingBlock;
    this.lvidsEndingBlock = this.lvidsStartingBlock + 4;

    this.physicalPartitionStartingBlock = this.lvidsEndingBlock;

    this.partitionToStoreMetadataOn = 0;

    this.fsdBlock = this.physicalPartitionStartingBlock + 1;
    this.fsdLocation = 1;
    this.rootFEBlock = this.physicalPartitionStartingBlock + 2;
    this.rootFELocation = 2;

    const currentBlock = this.recursiveGetFileEntryLocation(
      rootUDFImageBuilderFile,
      [this.rootFEBlock, 0],
      myUDFRevision
    );

    this.nextUniqueId = this.myUniqueIdDisposer.getNextUniqueId();
    this.physicalPartitionEndingBlock = currentBlock[0] + currentBlock[1];

    for (const myUdfImageFile of this.linearUDFImageBuilderFileOrdering) {
      if (myUdfImageFile.fileType === 'File') {
        if (Number(myUdfImageFile.fileEntryPosition.dataBlock) !== -1) {
          myUdfImageFile.fileEntryPosition.dataBlock += currentBlock[0];
          myUdfImageFile.fileEntryPosition.dataLocation +=
            myUdfImageFile.fileEntryPosition.dataBlock - this.physicalPartitionStartingBlock;
        }
      }
    }
    this.sizeTable = [];
    this.sizeTable[0] = this.physicalPartitionEndingBlock - this.physicalPartitionStartingBlock;
    this.freespaceTable = [];

    this.rvdsStartingBlock = this.physicalPartitionEndingBlock;
    this.rvdsEndingBlock = this.rvdsStartingBlock + 16;

    this.pvd2Block = this.rvdsStartingBlock;
    this.pd2Block = this.rvdsStartingBlock + 1;
    this.lvd2Block = this.rvdsStartingBlock + 2;
    this.usd2Block = this.rvdsStartingBlock + 3;
    this.iuvd2Block = this.rvdsStartingBlock + 4;
    this.td2Block = this.rvdsStartingBlock + 5;

    this.avdp2Block = this.rvdsEndingBlock + 1;
  }

  recursiveGetFileEntryLocation(currentUDFImageBuilderFile: any, currentBlock: any, myUDFRevision: any): any {
    const myFileEntryPosition = new FileEntryPositions();
    let block;
    if (currentUDFImageBuilderFile.identifier === '') {
      myFileEntryPosition.uniqueIds = 0;
    } else {
      myFileEntryPosition.uniqueIds = this.myUniqueIdDisposer.getNextUniqueId();
    }
    this.linearUDFImageBuilderFileOrdering.push(currentUDFImageBuilderFile);

    myFileEntryPosition.entryBlock = currentBlock[0];
    currentBlock[0]++;
    myFileEntryPosition.entryLocation = myFileEntryPosition.entryBlock - this.physicalPartitionStartingBlock;

    if (currentUDFImageBuilderFile.fileType === 'File') {
      if (currentUDFImageBuilderFile.getFileLength() > this.blockSize - 176) {
        myFileEntryPosition.dataBlock = currentBlock[1];
        currentBlock[1] += Math.ceil(currentUDFImageBuilderFile.getFileLength() / this.blockSize);
      } else {
        myFileEntryPosition.dataBlock = -1;
      }
    } else {
      let fidLength = 40;

      const childUDFImageBuilderFiles = currentUDFImageBuilderFile.getChildren();
      for (const cudfImageFile of childUDFImageBuilderFiles) {
        const cidentifier = cudfImageFile.identifier;

        const lengthWithoutPadding = 38 + stringToBytes1(cidentifier).length;
        const paddingLength = lengthWithoutPadding % 4 === 0 ? 0 : 4 - (lengthWithoutPadding % 4);
        const cfidLength = lengthWithoutPadding + paddingLength;
        fidLength += cfidLength;
      }
      if (fidLength > this.blockSize - 176) {
        myFileEntryPosition.dataBlock = currentBlock[0];
        myFileEntryPosition.dataLocation = myFileEntryPosition.dataBlock - this.physicalPartitionStartingBlock;
        currentBlock[0] += Math.ceil(fidLength / this.blockSize);
      } else {
        myFileEntryPosition.dataBlock = -1;
      }
      block = currentBlock;
      for (const childUDFImageBuilderFile of childUDFImageBuilderFiles) {
        block = this.recursiveGetFileEntryLocation(childUDFImageBuilderFile, block, myUDFRevision);
      }
    }
    currentUDFImageBuilderFile.fileEntryPosition = myFileEntryPosition;
    return block ? block : currentBlock;
  }
}
