/** @file
  Implementation of various string and line routines

  Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved. <BR>
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include "HexEditor.h"

extern BOOLEAN  HEditorMouseAction;

/**
  Free a line and it's internal buffer.

  @param[in] Src    The line to be freed.
**/
VOID
HLineFree (
  IN  HEFI_EDITOR_LINE  *Src
  )
{
  if (Src == NULL) {
    return;
  }

  SHELL_FREE_NON_NULL (Src);
}

/**
  Advance to the next Count lines.

  @param[in] Count      The line number to advance.

  @retval NULL An error occurred.
  @return A pointer to the line after advance.
**/
HEFI_EDITOR_LINE *
HLineAdvance (
  IN  UINTN  Count
  )
{
  UINTN             Index;
  HEFI_EDITOR_LINE  *Line;

  Line = HMainEditor.BufferImage->CurrentLine;
  if (Line == NULL) {
    return NULL;
  }

  for (Index = 0; Index < Count; Index++) {
    //
    // if already last line
    //
    if (Line->Link.ForwardLink == HMainEditor.BufferImage->ListHead) {
      return NULL;
    }

    Line = CR (Line->Link.ForwardLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
  }

  return Line;
}

/**
  Retreat to the previous Count lines.

  @param[in] Count    The line number to retreat.

  @retval NULL An error occurred.
  @return A pointer to the line after retreat.
**/
HEFI_EDITOR_LINE *
HLineRetreat (
  IN  UINTN  Count
  )
{
  UINTN             Index;
  HEFI_EDITOR_LINE  *Line;

  Line = HMainEditor.BufferImage->CurrentLine;
  if (Line == NULL) {
    return NULL;
  }

  for (Index = 0; Index < Count; Index++) {
    //
    // already the first line
    //
    if (Line->Link.BackLink == HMainEditor.BufferImage->ListHead) {
      return NULL;
    }

    Line = CR (Line->Link.BackLink, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
  }

  return Line;
}

/**
  Advance/Retreat lines.

  @param[in] Count      The line number to advance/retreat.
                            >0 : advance
                            <0: retreat

  @retval NULL An error occurred.
  @return A pointer to the line after move.
**/
HEFI_EDITOR_LINE *
HMoveLine (
  IN  INTN  Count
  )
{
  HEFI_EDITOR_LINE  *Line;
  UINTN             AbsCount;

  //
  // difference with MoveCurrentLine
  //     just return Line
  //     do not set currentline to Line
  //
  if (Count <= 0) {
    AbsCount = (UINTN)ABS (Count);
    Line     = HLineRetreat (AbsCount);
  } else {
    Line = HLineAdvance ((UINTN)Count);
  }

  return Line;
}

/**
  Advance/Retreat lines and set CurrentLine in BufferImage to it.

  @param[in] Count    The line number to advance/retreat.
                          >0 : advance
                          <0: retreat

  @retval NULL An error occurred.
  @return A pointer to the line after move.
**/
HEFI_EDITOR_LINE *
HMoveCurrentLine (
  IN  INTN  Count
  )
{
  HEFI_EDITOR_LINE  *Line;
  UINTN             AbsCount;

  //
  // <0: retreat
  // >0: advance
  //
  if (Count <= 0) {
    AbsCount = (UINTN)ABS (Count);
    Line     = HLineRetreat (AbsCount);
  } else {
    Line = HLineAdvance ((UINTN)Count);
  }

  if (Line == NULL) {
    return NULL;
  }

  HMainEditor.BufferImage->CurrentLine = Line;

  return Line;
}

/**
  Free all the lines in HBufferImage.
    Fields affected:
    Lines
    CurrentLine
    NumLines
    ListHead

  @param[in] ListHead     The list head.
  @param[in] Lines        The lines.

  @retval EFI_SUCCESS     The operation was successful.
**/
EFI_STATUS
HFreeLines (
  IN LIST_ENTRY        *ListHead,
  IN HEFI_EDITOR_LINE  *Lines
  )
{
  LIST_ENTRY        *Link;
  HEFI_EDITOR_LINE  *Line;

  //
  // release all the lines
  //
  if (Lines != NULL) {
    Line = Lines;
    Link = &(Line->Link);
    do {
      Line = CR (Link, HEFI_EDITOR_LINE, Link, EFI_EDITOR_LINE_LIST);
      Link = Link->ForwardLink;
      HLineFree (Line);
    } while (Link != ListHead);
  }

  ListHead->ForwardLink = ListHead;
  ListHead->BackLink    = ListHead;

  return EFI_SUCCESS;
}

/**
  Get the X information for the mouse.

  @param[in] GuidX      The change.

  @return the new information.
**/
INT32
HGetTextX (
  IN INT32  GuidX
  )
{
  INT32  Gap;

  HMainEditor.MouseAccumulatorX += GuidX;
  Gap                            = (HMainEditor.MouseAccumulatorX * (INT32)HMainEditor.ScreenSize.Column) / (INT32)(50 * (INT32)HMainEditor.MouseInterface->Mode->ResolutionX);
  HMainEditor.MouseAccumulatorX  = (HMainEditor.MouseAccumulatorX * (INT32)HMainEditor.ScreenSize.Column) % (INT32)(50 * (INT32)HMainEditor.MouseInterface->Mode->ResolutionX);
  HMainEditor.MouseAccumulatorX  = HMainEditor.MouseAccumulatorX / (INT32)HMainEditor.ScreenSize.Column;
  return Gap;
}

/**
  Get the Y information for the mouse.

  @param[in] GuidY      The change.

  @return the new information.
**/
INT32
HGetTextY (
  IN INT32  GuidY
  )
{
  INT32  Gap;

  HMainEditor.MouseAccumulatorY += GuidY;
  Gap                            = (HMainEditor.MouseAccumulatorY * (INT32)HMainEditor.ScreenSize.Row) / (INT32)(50 * (INT32)HMainEditor.MouseInterface->Mode->ResolutionY);
  HMainEditor.MouseAccumulatorY  = (HMainEditor.MouseAccumulatorY * (INT32)HMainEditor.ScreenSize.Row) % (INT32)(50 * (INT32)HMainEditor.MouseInterface->Mode->ResolutionY);
  HMainEditor.MouseAccumulatorY  = HMainEditor.MouseAccumulatorY / (INT32)HMainEditor.ScreenSize.Row;

  return Gap;
}
