// Copyright 2014 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 "../../include/fpdfdoc/fpdf_doc.h"
CPDF_Dest CPDF_Action::GetDest(CPDF_Document* pDoc) const
{
    if (!m_pDict) {
        return CPDF_Dest();
    }
    CFX_ByteString type = m_pDict->GetString("S");
    if (type != "GoTo" && type != "GoToR") {
        return CPDF_Dest();
    }
    CPDF_Object* pDest = m_pDict->GetElementValue("D");
    if (!pDest) {
        return CPDF_Dest();
    }
    if (pDest->GetType() == PDFOBJ_STRING || pDest->GetType() == PDFOBJ_NAME) {
        CPDF_NameTree name_tree(pDoc, FX_BSTRC("Dests"));
        CFX_ByteStringC name = pDest->GetString();
        return CPDF_Dest(name_tree.LookupNamedDest(pDoc, name));
    }
    if (pDest->GetType() == PDFOBJ_ARRAY) {
        return CPDF_Dest((CPDF_Array*)pDest);
    }
    return CPDF_Dest();
}
const FX_CHAR* g_sATypes[] = {"Unknown", "GoTo", "GoToR", "GoToE", "Launch", "Thread", "URI", "Sound", "Movie",
                              "Hide",	"Named", "SubmitForm", "ResetForm", "ImportData", "JavaScript", "SetOCGState",
                              "Rendition", "Trans", "GoTo3DView", ""
                             };
CPDF_Action::ActionType CPDF_Action::GetType() const
{
    ActionType eType = Unknown;
    if (m_pDict != NULL) {
        CFX_ByteString csType = m_pDict->GetString("S");
        if (!csType.IsEmpty()) {
            int i = 0;
            while (g_sATypes[i][0] != '\0') {
                if (csType == g_sATypes[i]) {
                    return (ActionType)i;
                }
                i ++;
            }
        }
    }
    return eType;
}
CFX_WideString CPDF_Action::GetFilePath() const
{
    CFX_ByteString type = m_pDict->GetString("S");
    if (type != "GoToR" && type != "Launch" &&
            type != "SubmitForm" && type != "ImportData") {
        return CFX_WideString();
    }
    CPDF_Object* pFile = m_pDict->GetElementValue("F");
    CFX_WideString path;
    if (pFile == NULL) {
        if (type == "Launch") {
            CPDF_Dictionary* pWinDict = m_pDict->GetDict(FX_BSTRC("Win"));
            if (pWinDict) {
                return CFX_WideString::FromLocal(pWinDict->GetString(FX_BSTRC("F")));
            }
        }
        return path;
    }
    CPDF_FileSpec filespec(pFile);
    filespec.GetFileName(path);
    return path;
}
CFX_ByteString CPDF_Action::GetURI(CPDF_Document* pDoc) const
{
    CFX_ByteString csURI;
    if (m_pDict == NULL) {
        return csURI;
    }
    if (m_pDict->GetString("S") != "URI") {
        return csURI;
    }
    csURI = m_pDict->GetString("URI");
    CPDF_Dictionary* pRoot = pDoc->GetRoot();
    CPDF_Dictionary* pURI = pRoot->GetDict("URI");
    if (pURI != NULL) {
        if (csURI.Find(FX_BSTRC(":"), 0) < 1) {
            csURI = pURI->GetString("Base") + csURI;
        }
    }
    return csURI;
}
FX_DWORD CPDF_ActionFields::GetFieldsCount() const
{
    if (m_pAction == NULL) {
        return 0;
    }
    CPDF_Dictionary* pDict = m_pAction->GetDict();
    if (pDict == NULL) {
        return 0;
    }
    CFX_ByteString csType = pDict->GetString("S");
    CPDF_Object* pFields = NULL;
    if (csType == "Hide") {
        pFields = pDict->GetElementValue("T");
    } else {
        pFields = pDict->GetArray("Fields");
    }
    if (pFields == NULL) {
        return 0;
    }
    int iType = pFields->GetType();
    if (iType == PDFOBJ_DICTIONARY) {
        return 1;
    }
    if (iType == PDFOBJ_STRING) {
        return 1;
    }
    if (iType == PDFOBJ_ARRAY) {
        return ((CPDF_Array*)pFields)->GetCount();
    }
    return 0;
}
void CPDF_ActionFields::GetAllFields(CFX_PtrArray& fieldObjects) const
{
    fieldObjects.RemoveAll();
    if (m_pAction == NULL) {
        return;
    }
    CPDF_Dictionary* pDict = m_pAction->GetDict();
    if (pDict == NULL) {
        return;
    }
    CFX_ByteString csType = pDict->GetString("S");
    CPDF_Object* pFields = NULL;
    if (csType == "Hide") {
        pFields = pDict->GetElementValue("T");
    } else {
        pFields = pDict->GetArray("Fields");
    }
    if (pFields == NULL) {
        return;
    }
    int iType = pFields->GetType();
    if (iType == PDFOBJ_DICTIONARY || iType == PDFOBJ_STRING) {
        fieldObjects.Add(pFields);
    } else if (iType == PDFOBJ_ARRAY) {
        CPDF_Array* pArray = (CPDF_Array*)pFields;
        FX_DWORD iCount = pArray->GetCount();
        for (FX_DWORD i = 0; i < iCount; i ++) {
            CPDF_Object* pObj = pArray->GetElementValue(i);
            if (pObj != NULL) {
                fieldObjects.Add(pObj);
            }
        }
    }
}
CPDF_Object* CPDF_ActionFields::GetField(FX_DWORD iIndex) const
{
    if (m_pAction == NULL) {
        return NULL;
    }
    CPDF_Dictionary* pDict = m_pAction->GetDict();
    if (pDict == NULL) {
        return NULL;
    }
    CFX_ByteString csType = pDict->GetString("S");
    CPDF_Object* pFields = NULL;
    if (csType == "Hide") {
        pFields = pDict->GetElementValue("T");
    } else {
        pFields = pDict->GetArray("Fields");
    }
    if (pFields == NULL) {
        return NULL;
    }
    CPDF_Object* pFindObj = NULL;
    int iType = pFields->GetType();
    if (iType == PDFOBJ_DICTIONARY || iType == PDFOBJ_STRING) {
        if (iIndex == 0) {
            pFindObj = pFields;
        }
    } else if (iType == PDFOBJ_ARRAY) {
        pFindObj = ((CPDF_Array*)pFields)->GetElementValue(iIndex);
    }
    return pFindObj;
}
CPDF_LWinParam CPDF_Action::GetWinParam() const
{
    if (m_pDict == NULL) {
        return NULL;
    }
    if (m_pDict->GetString("S") != "Launch") {
        return NULL;
    }
    return m_pDict->GetDict("Win");
}
CFX_WideString CPDF_Action::GetJavaScript() const
{
    CFX_WideString csJS;
    if (m_pDict == NULL) {
        return csJS;
    }
    CPDF_Object* pJS = m_pDict->GetElementValue("JS");
    if (pJS != NULL) {
        return pJS->GetUnicodeText();
    }
    return csJS;
}
CPDF_Dictionary* CPDF_Action::GetAnnot() const
{
    if (!m_pDict) {
        return nullptr;
    }
    CFX_ByteString csType = m_pDict->GetString("S");
    if (csType == FX_BSTRC("Rendition")) {
        return m_pDict->GetDict("AN");
    }
    if (csType == FX_BSTRC("Movie")) {
        return m_pDict->GetDict("Annotation");
    }
    return nullptr;
}
int32_t CPDF_Action::GetOperationType() const
{
    if (m_pDict == NULL) {
        return 0;
    }
    CFX_ByteString csType = m_pDict->GetString("S");
    if (csType == FX_BSTRC("Rendition")) {
        return m_pDict->GetInteger("OP");
    }
    if (csType == FX_BSTRC("Movie")) {
        CFX_ByteString csOP = m_pDict->GetString("Operation");
        if (csOP == FX_BSTRC("Play")) {
            return 0;
        }
        if (csOP == FX_BSTRC("Stop")) {
            return 1;
        }
        if (csOP == FX_BSTRC("Pause")) {
            return 2;
        }
        if (csOP == FX_BSTRC("Resume")) {
            return 3;
        }
    }
    return 0;
}
FX_DWORD CPDF_Action::GetSubActionsCount() const
{
    if (m_pDict == NULL || !m_pDict->KeyExist("Next")) {
        return 0;
    }
    CPDF_Object* pNext = m_pDict->GetElementValue("Next");
    if (!pNext) {
        return 0;
    }
    int iObjType = pNext->GetType();
    if (iObjType == PDFOBJ_DICTIONARY) {
        return 1;
    }
    if (iObjType == PDFOBJ_ARRAY) {
        return ((CPDF_Array*)pNext)->GetCount();
    }
    return 0;
}
CPDF_Action CPDF_Action::GetSubAction(FX_DWORD iIndex) const
{
    if (m_pDict == NULL || !m_pDict->KeyExist("Next")) {
        return CPDF_Action();
    }
    CPDF_Object* pNext = m_pDict->GetElementValue("Next");
    int iObjType = pNext->GetType();
    if (iObjType == PDFOBJ_DICTIONARY) {
        CPDF_Dictionary *pDict = static_cast<CPDF_Dictionary*>(pNext);
        if (iIndex == 0) {
            return CPDF_Action(pDict);
        }
    } else if (iObjType == PDFOBJ_ARRAY) {
        CPDF_Array* pArray = static_cast<CPDF_Array*>(pNext);
        return CPDF_Action(pArray->GetDict(iIndex));
    }
    return CPDF_Action();
}
const FX_CHAR* g_sAATypes[] = {"E", "X", "D", "U", "Fo", "Bl", "PO", "PC", "PV", "PI",
                               "O", "C",
                               "K", "F", "V", "C",
                               "WC", "WS", "DS", "WP", "DP",
                               ""
                              };
FX_BOOL CPDF_AAction::ActionExist(AActionType eType) const
{
    if (m_pDict == NULL) {
        return FALSE;
    }
    return m_pDict->KeyExist(g_sAATypes[(int)eType]);
}
CPDF_Action CPDF_AAction::GetAction(AActionType eType) const
{
    if (!m_pDict) {
        return CPDF_Action();
    }
    return CPDF_Action(m_pDict->GetDict(g_sAATypes[(int)eType]));
}
FX_POSITION CPDF_AAction::GetStartPos() const
{
    if (m_pDict == NULL) {
        return NULL;
    }
    return m_pDict->GetStartPos();
}
CPDF_Action CPDF_AAction::GetNextAction(FX_POSITION& pos, AActionType& eType) const
{
    if (m_pDict == NULL) {
        return CPDF_Action();
    }
    CFX_ByteString csKey;
    CPDF_Object* pObj = m_pDict->GetNextElement(pos, csKey);
    if (!pObj) {
        return CPDF_Action();
    }
    CPDF_Object* pDirect = pObj->GetDirect();
    if (!pDirect || pDirect->GetType() != PDFOBJ_DICTIONARY) {
        return CPDF_Action();
    }
    int i = 0;
    while (g_sAATypes[i][0] != '\0') {
        if (csKey == g_sAATypes[i]) {
            break;
        }
        i++;
    }
    eType = (AActionType)i;
    return CPDF_Action(static_cast<CPDF_Dictionary*>(pDirect));
}
CPDF_DocJSActions::CPDF_DocJSActions(CPDF_Document* pDoc)
{
    m_pDocument = pDoc;
}
int CPDF_DocJSActions::CountJSActions() const
{
    ASSERT(m_pDocument != NULL);
    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
    return name_tree.GetCount();
}
CPDF_Action CPDF_DocJSActions::GetJSAction(int index, CFX_ByteString& csName) const
{
    ASSERT(m_pDocument != NULL);
    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
    CPDF_Object *pAction = name_tree.LookupValue(index, csName);
    if (pAction == NULL || pAction->GetType() != PDFOBJ_DICTIONARY) {
        return CPDF_Action();
    }
    return CPDF_Action(pAction->GetDict());
}
CPDF_Action CPDF_DocJSActions::GetJSAction(const CFX_ByteString& csName) const
{
    ASSERT(m_pDocument != NULL);
    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
    CPDF_Object *pAction = name_tree.LookupValue(csName);
    if (pAction == NULL || pAction->GetType() != PDFOBJ_DICTIONARY) {
        return CPDF_Action();
    }
    return CPDF_Action(pAction->GetDict());
}
int CPDF_DocJSActions::FindJSAction(const CFX_ByteString& csName) const
{
    ASSERT(m_pDocument != NULL);
    CPDF_NameTree name_tree(m_pDocument, FX_BSTRC("JavaScript"));
    return name_tree.GetIndex(csName);
}