// Copyright 2016 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com

#include "xfa/fxfa/parser/cxfa_box.h"

#include "xfa/fxfa/parser/cxfa_corner.h"
#include "xfa/fxfa/parser/cxfa_measurement.h"
#include "xfa/fxfa/parser/xfa_object.h"

namespace {

void GetStrokesInternal(CXFA_Node* pNode,
                        CXFA_StrokeArray& strokes,
                        FX_BOOL bNull) {
  strokes.RemoveAll();
  if (!pNode)
    return;

  strokes.SetSize(8);
  int32_t i, j;
  for (i = 0, j = 0; i < 4; i++) {
    CXFA_Corner corner =
        CXFA_Corner(pNode->GetProperty(i, XFA_Element::Corner, i == 0));
    if (corner || i == 0)
      strokes.SetAt(j, corner);
    else if (bNull)
      strokes.SetAt(j, CXFA_Stroke(nullptr));
    else if (i == 1)
      strokes.SetAt(j, strokes[0]);
    else if (i == 2)
      strokes.SetAt(j, strokes[0]);
    else
      strokes.SetAt(j, strokes[2]);

    j++;
    CXFA_Edge edge =
        CXFA_Edge(pNode->GetProperty(i, XFA_Element::Edge, i == 0));
    if (edge || i == 0)
      strokes.SetAt(j, edge);
    else if (bNull)
      strokes.SetAt(j, CXFA_Stroke(nullptr));
    else if (i == 1)
      strokes.SetAt(j, strokes[1]);
    else if (i == 2)
      strokes.SetAt(j, strokes[1]);
    else
      strokes.SetAt(j, strokes[3]);

    j++;
  }
}

static int32_t Style3D(const CXFA_StrokeArray& strokes, CXFA_Stroke& stroke) {
  int32_t iCount = strokes.GetSize();
  if (iCount < 1)
    return 0;

  stroke = strokes[0];
  for (int32_t i = 1; i < iCount; i++) {
    CXFA_Stroke find = strokes[i];
    if (!find)
      continue;

    if (!stroke)
      stroke = find;
    else if (stroke.GetStrokeType() != find.GetStrokeType())
      stroke = find;
    break;
  }
  int32_t iType = stroke.GetStrokeType();
  if (iType == XFA_ATTRIBUTEENUM_Lowered || iType == XFA_ATTRIBUTEENUM_Raised ||
      iType == XFA_ATTRIBUTEENUM_Etched ||
      iType == XFA_ATTRIBUTEENUM_Embossed) {
    return iType;
  }
  return 0;
}

}  // namespace

int32_t CXFA_Box::GetHand() const {
  if (!m_pNode)
    return XFA_ATTRIBUTEENUM_Even;
  return m_pNode->GetEnum(XFA_ATTRIBUTE_Hand);
}

int32_t CXFA_Box::GetPresence() const {
  if (!m_pNode)
    return XFA_ATTRIBUTEENUM_Hidden;
  return m_pNode->GetEnum(XFA_ATTRIBUTE_Presence);
}

int32_t CXFA_Box::CountEdges() const {
  if (!m_pNode)
    return 0;
  return m_pNode->CountChildren(XFA_Element::Edge);
}

CXFA_Edge CXFA_Box::GetEdge(int32_t nIndex) const {
  return CXFA_Edge(
      m_pNode ? m_pNode->GetProperty(nIndex, XFA_Element::Edge, nIndex == 0)
              : nullptr);
}

void CXFA_Box::GetStrokes(CXFA_StrokeArray& strokes) const {
  GetStrokesInternal(m_pNode, strokes, FALSE);
}

FX_BOOL CXFA_Box::IsCircular() const {
  if (!m_pNode)
    return FALSE;
  return m_pNode->GetBoolean(XFA_ATTRIBUTE_Circular);
}

FX_BOOL CXFA_Box::GetStartAngle(FX_FLOAT& fStartAngle) const {
  fStartAngle = 0;
  if (!m_pNode)
    return FALSE;

  CXFA_Measurement ms;
  FX_BOOL bRet = m_pNode->TryMeasure(XFA_ATTRIBUTE_StartAngle, ms, FALSE);
  if (bRet)
    fStartAngle = ms.GetValue();

  return bRet;
}

FX_BOOL CXFA_Box::GetSweepAngle(FX_FLOAT& fSweepAngle) const {
  fSweepAngle = 360;
  if (!m_pNode)
    return FALSE;

  CXFA_Measurement ms;
  FX_BOOL bRet = m_pNode->TryMeasure(XFA_ATTRIBUTE_SweepAngle, ms, FALSE);
  if (bRet)
    fSweepAngle = ms.GetValue();

  return bRet;
}

CXFA_Fill CXFA_Box::GetFill(FX_BOOL bModified) const {
  if (!m_pNode)
    return CXFA_Fill(nullptr);

  CXFA_Node* pFillNode = m_pNode->GetProperty(0, XFA_Element::Fill, bModified);
  return CXFA_Fill(pFillNode);
}

CXFA_Margin CXFA_Box::GetMargin() const {
  return CXFA_Margin(m_pNode ? m_pNode->GetChild(0, XFA_Element::Margin)
                             : nullptr);
}

int32_t CXFA_Box::Get3DStyle(FX_BOOL& bVisible, FX_FLOAT& fThickness) const {
  if (IsArc())
    return 0;

  CXFA_StrokeArray strokes;
  GetStrokesInternal(m_pNode, strokes, TRUE);
  CXFA_Stroke stroke(nullptr);
  int32_t iType = Style3D(strokes, stroke);
  if (iType) {
    bVisible = stroke.IsVisible();
    fThickness = stroke.GetThickness();
  }
  return iType;
}