/**
 * Copyright 2015 CANAL+ Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import log from "../../../log";
import isNonEmptyString from "../../../utils/is_non_empty_string";

const CELL_RESOLUTION_REGEXP = /(\d+) (\d+)/;

export interface ITTParameters {
  frameRate: number;
  subFrameRate: number;
  tickRate: number;
  spaceStyle: "default" | "preserve";
  cellResolution: { columns: number; rows: number };
}

/**
 * Returns global parameters from a TTML Document
 * @param {Element} tt - <tt> node
 * @throws Error - Throws if the spacing style is invalid.
 * @returns {Object}
 */
export default function getParameters(tt: Element): ITTParameters {
  const parsedFrameRate = tt.getAttribute("ttp:frameRate");
  const parsedSubFrameRate = tt.getAttribute("ttp:subFramRate");
  const parsedTickRate = tt.getAttribute("ttp:tickRate");
  const parsedFrameRateMultiplier = tt.getAttribute("ttp:frameRateMultiplier");
  const parsedSpaceStyle = tt.getAttribute("xml:space");
  const parsedCellResolution = tt.getAttribute("ttp:cellResolution");

  let cellResolution: { columns: number; rows: number } = {
    columns: 32,
    rows: 15,
  };
  if (parsedCellResolution !== null) {
    const extractedData = CELL_RESOLUTION_REGEXP.exec(parsedCellResolution);
    if (extractedData === null || extractedData.length < 3) {
      log.warn("ttml", "Invalid cellResolution", {
        cellResolution: parsedCellResolution,
      });
    } else {
      const columns = parseInt(extractedData[1], 10);
      const rows = parseInt(extractedData[2], 10);
      if (isNaN(columns) || isNaN(rows)) {
        log.warn("ttml", "Invalid cellResolution", {
          cellResolution: parsedCellResolution,
        });
      } else {
        cellResolution = { columns, rows };
      }
    }
  }

  if (
    isNonEmptyString(parsedSpaceStyle) &&
    parsedSpaceStyle !== "default" &&
    parsedSpaceStyle !== "preserve"
  ) {
    throw new Error("Invalid spacing style");
  }

  let nbFrameRate = Number(parsedFrameRate);
  if (isNaN(nbFrameRate) || nbFrameRate <= 0) {
    nbFrameRate = 30;
  }
  let nbSubFrameRate = Number(parsedSubFrameRate);
  if (isNaN(nbSubFrameRate) || nbSubFrameRate <= 0) {
    nbSubFrameRate = 1;
  }
  let nbTickRate: number | undefined = Number(parsedTickRate);
  if (isNaN(nbTickRate) || nbTickRate <= 0) {
    nbTickRate = undefined;
  }

  let frameRate = nbFrameRate;
  const subFrameRate = nbSubFrameRate ?? 1;
  const spaceStyle = parsedSpaceStyle ?? "default";

  const tickRate = nbTickRate ?? nbFrameRate * nbSubFrameRate;

  if (parsedFrameRateMultiplier !== null) {
    const multiplierResults = /^(\d+) (\d+)$/g.exec(parsedFrameRateMultiplier);
    if (multiplierResults !== null) {
      const numerator = Number(multiplierResults[1]);
      const denominator = Number(multiplierResults[2]);
      const multiplierNum = numerator / denominator;
      frameRate = nbFrameRate * multiplierNum;
    }
  }

  return { cellResolution, tickRate, frameRate, subFrameRate, spaceStyle };
}
