/*
	Antenna House PDF Tool API V8.0
	C++ Interface sample program

	概要：テキストエレメント情報取得の例

	Copyright 2025- Antenna House, Inc.
*/

#include < PdfTk.h >
#include < stdio.h >
#include < string >

using namespace std;
using namespace PdfTk;

static void addStamp(PtlPage& page);
static void addAnnot(PtlPage& page);
static void addOutline(PtlPage& page, PtlOutline& outlineRoot, int pg);
static string writeColor(PtlColor* clr);

int main(int argc, char* argv[])
{
	if (argc < 3) {
		printf("usage: EditElement.exe in-pdf-file out-pdf-file\n");
		return 1;
	}

	try
	{
		PtlParamInput input(argv[1]);
		PtlParamOutput output(argv[2]);

		PtlPDFDocument doc;

		// PDFファイルをロードします。
		doc.load(input);

        // ページコンテナの取得
		PtlPages& pages = doc.getPages();

		if (pages.isEmpty()){
			printf("ページコンテナが空\n");
			return 1;
		}

        int pageCount = pages.getCount();
        if (pageCount >= 1)
        {
            PtlPage page1 = pages.get(0);	//1ページ目
            //「ごん狐」の箇所にスタンプを置く例
            addStamp(page1);
        }

        if (pageCount >= 2)
        {
            PtlPage page2 = pages.get(1);	//2ページ目
            //「兵十」に注釈を置く例
            addAnnot(page2);
        }

        if (pageCount >= 3)
        {
            PtlPage page3 = pages.get(2);	//3ページ目
            // 文字列を元にしおりを作成する例
            PtlOutline outlineRoot = doc.getRootOutline();
            addOutline(page3, outlineRoot, 2);
        }

        doc.save(output);

		printf("完了!\n");
	}
	catch (const PtlException &e)
	{
		fprintf(stderr, "Error code : %d\n %s\n", e.getErrorCode(), e.getErrorMessage().c_str());
		return 1;
	}
	return 0;
}

static void addStamp(PtlPage& page)
{
    // 「ごん狐」の箇所にスタンプを置く例
    PtlContent content = page.getContent();
    PtlEditElements elements = content.getEditElements();
    int elemCnt = elements.getCount();
    for (int i = 0; i < elemCnt; ++i)
    {
        PtlEditElement& element = elements.get(i);
        if (element.getType() == PtlEditElement::ELEMENT_TYPE::TYPE_TEXT)
        {
            PtlEditText* textObj = dynamic_cast< PtlEditText* >(&element);
            // dynamic_cast の結果を必ずチェック
            if (textObj == nullptr) {
                printf("addStamp: textObj == nullptr, skip\n");
                continue;
            }
            PtlEditTextItems items = textObj->getTextItems();
            int itemCnt = items.getCount();
            for (int j = 0; j < itemCnt; ++j)
            {
                PtlEditTextItem item = items.get(j);
                // "ごん狐"の位置にスタンプを追加する
                if (std::string(item.getText().c_str()) == "ごん狐")
                {
                    PtlAnnots annots = page.getAnnots();
                    PtlAnnotStamp* stampAnnot1 = new PtlAnnotStamp();
                    PtlRect recB = item.getBBox();
                    stampAnnot1->setRect(recB);
                    stampAnnot1->setIconType(PtlAnnotStamp::ICON_TYPE::ICON_APPROVED);
                    stampAnnot1->setAnnotFlags(PtlAnnot::ANNOT_FLAGS::FLAG_PRINT);
                    annots.append(*stampAnnot1);
                    delete stampAnnot1;
                }
            }
        }
    }
}

static void addAnnot(PtlPage& page)
{
    // 「兵十」に注釈を置く例
    PtlContent content = page.getContent();
    PtlEditElements elements = content.getEditElements();
    int elemCnt = elements.getCount();
    for (int i = 0; i < elemCnt; ++i)
    {
        // 参照で受け取ってスライスを防止
        PtlEditElement& element = elements.get(i);
        if (element.getType() == PtlEditElement::ELEMENT_TYPE::TYPE_TEXT)
        {
            PtlEditText* textObj = dynamic_cast< PtlEditText* >(&element);
            // dynamic_cast の結果を必ずチェック
            if (textObj == nullptr) {
                printf("addAnnot: textObj == nullptr, skip\n");
                continue;
            }
            PtlEditTextItems items = textObj->getTextItems();
            int itemCnt = items.getCount();
            for (int j = 0; j < itemCnt; ++j)
            {
                PtlEditTextItem item = items.get(j);
                if (std::string(item.getText().c_str()) == "兵十")
                {
                    PtlAnnots annots = page.getAnnots();
                    PtlAnnotText* annottext = new PtlAnnotText();
                    annottext->setIconType(PtlAnnotText::ICON_TYPE::ICON_COMMENT);
                    annottext->setRect(item.getBBox());

                    PtlRect recB = item.getBBox();
                    string str = "Rect (" + to_string(recB.getLeft()) + ", " + to_string(recB.getBottom()) + ", " + to_string(recB.getRight()) + ", " + to_string(recB.getTop()) + ")\n";

                    PtlQuadPoint qpoint = item.getQuadPoint();
                    str += "QuadPoint : TopLeft (" + to_string(qpoint.getTopLeft().getX()) + ", " + to_string(qpoint.getTopLeft().getY()) + ")\n";
                    str += "QuadPoint : TopRight (" + to_string(qpoint.getTopRight().getX()) + ", " + to_string(qpoint.getTopRight().getY()) + ")\n";
                    str += "QuadPoint : BottomLeft (" + to_string(qpoint.getBottomLeft().getX()) + ", " + to_string(qpoint.getBottomLeft().getY()) + ")\n";
                    str += "QuadPoint : BottomRight (" + to_string(qpoint.getBottomRight().getX()) + ", " + to_string(qpoint.getBottomRight().getY()) + ")\n";
                    PtlFontInfo fontInfo = item.getFontInfo();
                    str += "FontName : ";
                    str += fontInfo.getFontName().c_str();
                    str += "\n";
                    str += fontInfo.isEmbedded() ? "isEmbedded : true\n" : "isEmbedded : false\n";

                    str += "ペイントフラグ：\n";
                    if (static_cast< PtlEditTextItem::PAINT_FLAGS >(item.getPaintFlags()) & PtlEditTextItem::PAINT_FLAGS::PAINT_FILL)
                    {
                        PtlColor clr = item.getFillColor();
                        str += " PAINT_FILL" + writeColor(&clr) + "\n";
                    }
                    if (static_cast< PtlEditTextItem::PAINT_FLAGS >(item.getPaintFlags()) & PtlEditTextItem::PAINT_FLAGS::PAINT_STROKE)
                    {
                        PtlColor clr = item.getStrokeColor();
                        str += " PAINT_STROKE" + writeColor(&clr) + "\n";
                    }

                    annottext->setTextContents(PtlParamString(str.c_str()));

                    time_t t = time(nullptr);
                    tm now;
                    localtime_s(&now, &t);
                    PtlDate* date = new PtlDate(now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec);
                    annottext->setDate(*date);
                    delete date;

                    annottext->setAnnotFlags(PtlAnnotText::ANNOT_FLAGS::FLAG_NOROTATE);

                    PtlColor fillColor = item.getFillColor();
                    if (fillColor.getType() == PtlColor::COLOR_TYPE::TYPE_DEVICE_RGB)
                    {
                        PtlColorDeviceRGB* color = static_cast< PtlColorDeviceRGB*>(&fillColor);
                        if (color != nullptr)
                        {
                            annottext->setColor(*color);
                        }
                    }

                    annottext->setBorderStyle(PtlAnnotText::BORDER_STYLE::BORDER_SOLID);
                    annottext->setBorderWidth(PtlAnnotText::BORDER_LINE_WIDTH::BORDER_WIDTH_THIN);

                    annottext->setMarkUpTitle(item.getText());
                    annottext->setMarkUpSubj(PtlParamString(to_string(item.getPaintFlags()).c_str()));

                    date = new PtlDate(now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec);
                    annottext->setMarkUpDate(*date);
                    delete date;

                    annottext->setMarkUpCA(0.6f);

                    annots.append(*annottext);
                    delete annottext;
                }
            }
        }
    }
}

static void addOutline(PtlPage& page, PtlOutline& outlineRoot, int pg)
{
    // 赤と青の文字列を元にしおりを作成する例
    PtlContent content = page.getContent();
    PtlEditElements elements = content.getEditElements();
    int elemCnt = elements.getCount();
    for (int i = 0; i < elemCnt; ++i)
    {
        PtlEditElement& element = elements.get(i);
        if (element.getType() == PtlEditElement::ELEMENT_TYPE::TYPE_TEXT)
        {
            PtlEditText* textObj = dynamic_cast< PtlEditText*>(&element);
            if (textObj == nullptr) continue;
            PtlEditTextItems items = textObj->getTextItems();
            int itemCnt = items.getCount();
            for (int j = 0; j < itemCnt; ++j)
            {
                PtlEditTextItem item = items.get(j);
                PtlColor fillColorBase = item.getFillColor();
                if (fillColorBase.getType() == PtlColor::COLOR_TYPE::TYPE_DEVICE_RGB)
                {
                    PtlColorDeviceRGB* color = static_cast< PtlColorDeviceRGB* >(&fillColorBase);
                    if (color != nullptr)
                    {
                        // outline をここで定義
                        PtlOutline* outline = new PtlOutline();

                        // テキストの塗りつぶし色が青か赤のとき
                        if ((color->getR() == 0.0f && color->getG() == 0.0f && color->getB() == 1.0f)
                            || (color->getR() == 1.0f && color->getG() == 0.0f && color->getB() == 0.0f))
                        {
                            outline->setColor(*color);
                            outline->setTitle(item.getText());

                            PtlActionGoTo* actiongoto = new PtlActionGoTo();
                            PtlDestXYZ* destxyz = new PtlDestXYZ();
                            destxyz->setPageNumber(pg);
                            PtlRect recB = item.getBBox();
                            destxyz->setBottom(recB.getBottom());
                            destxyz->setTop(recB.getTop());
                            destxyz->setLeft(recB.getLeft());
                            destxyz->setRight(recB.getRight());
                            actiongoto->setDest(*destxyz);
                            outline->setAction(*actiongoto);

                            outline->setFlags(PtlOutline::ITEM_FLAG::FLAG_NORMAL);
                            outline->setOpen(true);

                            outlineRoot.appendLastChild(*outline);

                            delete actiongoto;
                            delete destxyz;
                            delete outline;
                        }
                    }
                }
            }
        }
    }
}

static string writeColor(PtlColor* clr)
{
    string str;
    switch (clr->getType())
    {
    case PtlColor::COLOR_TYPE::TYPE_DEVICE_RGB:
    {
        PtlColorDeviceRGB* rgbColor = static_cast< PtlColorDeviceRGB* >(clr);
        str = " : DEVICE_RGB  : (" + to_string(rgbColor->getR()) + ", " + to_string(rgbColor->getG()) + ", " + to_string(rgbColor->getB()) + ")";
        break;
    }
    case PtlColor::COLOR_TYPE::TYPE_DEVICE_CMYK:
    {
        PtlColorDeviceCMYK* cmykColor = static_cast< PtlColorDeviceCMYK* >(clr);
        str = " : DEVICE_CMYK (" + to_string(cmykColor->getC()) + ", " + to_string(cmykColor->getM()) + ", " + to_string(cmykColor->getY()) + ", " + to_string(cmykColor->getK()) + ")";
        break;
    }
    case PtlColor::COLOR_TYPE::TYPE_DEVICE_GRAY:
    {
        PtlColorDeviceGray* gryColor = static_cast< PtlColorDeviceGray* >(clr);
        str = " : DEVICE_GRAY (" + to_string(gryColor->getGray()) + ")";
        break;
    }
    case PtlColor::COLOR_TYPE::TYPE_NONE:
        str = " : COLOR_TYPE.TYPE_NONE";
        break;
    case PtlColor::COLOR_TYPE::TYPE_UNKNOWN:
        str = " : COLOR_TYPE.TYPE_UNKNOWN";
        break;
    }
    return str;
}