#include "Button.h"

#include "AlphaField.h"
#include "Border.h"
#include "File.h"
#include "FileSystem.h"
#include "Font.h"
#include "Globals.h"
#include "Image.h"
#include "KeyboardEvent.h"
#include "MouseEvent.h"
#include "Scroll.h"
#include "Text.h"
#include "ToolTip.h"

using namespace Framework;

// Contents of the Button class from Button.h
// Constructor
Button::Button()
    : TextField(),
      klickColor(0xFF000000),
      clickImage(0),
      klickBuffer(0),
      klickIndex(0)
{
    style
        = Style::Allowed | Style::Buffered | Style::ClickBuffer | Style::Border;
    this->setMouseEvent(_ret1ME);
    setFontColor(0xFFFFFFFF);
    setFontSize(12);
    setBorderWidth(2);
    setBorderColor(0xFF00FF00);
    setAlphaFieldColor(0x5500FF00);
    setAlphaFieldStrength(-5);
    setKBColor(0xFF000000);
    setKBStrength(20);
    addStyle(TextField::Style::Center);
}

// Destructor
Button::~Button()
{
    if (klickBuffer) klickBuffer->release();
    if (clickImage) clickImage->release();
}

void Button::doMouseEvent(MouseEvent& me, bool userRet) // Mouse event
{
    if (hasStyleNot(Style::Allowed) || !userRet) return;
    if (me.id == ME_Enter)
    {
        klickIndex = MouseState[M_Left];
        if (klickIndex) rend = 1;
    }
    if (me.id == ME_RLeft || me.id == ME_Leaves)
    {
        if (klickIndex) rend = 1;
        klickIndex = 0;
    }
    if (!me.processed)
    {
        if (me.id == ME_PLeft)
        {
            klickIndex = 1;
            rend = 1;
        }
        me.processed = 1;
    }
}

// non-constant
void Button::setClickColor(int fc) // sets the click color
{
    klickColor = fc;
    rend = 1;
}

void Button::setClickImage(Image* bild) // sets the click image
{
    if (bild)
    {
        if (!clickImage) clickImage = new Image();
        clickImage->newImage(bild->getWidth(), bild->getHeight(), 0);
        int* buff1 = clickImage->getBuffer();
        int* buff2 = bild->getBuffer();
        for (int i = 0; i < bild->getWidth() * bild->getHeight(); ++i)
            buff1[i] = buff2[i];
        bild->release();
        rend = 1;
    }
}

void Button::setClickImageZ(Image* bild) // sets a pointer to the click image
{
    if (clickImage) clickImage->release();
    clickImage = bild;
    rend = 1;
}

void Button::setKBZ(AlphaField* af)
{
    if (klickBuffer) klickBuffer->release();
    klickBuffer = af;
    rend = 1;
}

void Button::setKBStrength(int st) // sets the click buffer strength
{
    if (!klickBuffer) klickBuffer = new AlphaField();
    klickBuffer->setStrength(st);
    rend = 1;
}

void Button::setKBColor(int fc) // sets the click buffer color
{
    if (!klickBuffer) klickBuffer = new AlphaField();
    klickBuffer->setColor(fc);
    rend = 1;
}

// Processes mouse messages
//  te: The event triggered by the keyboard input
void Button::doKeyboardEvent(KeyboardEvent& te) {}

void Button::render(Image& zRObj) // renders int zRObj
{
    if (!hasStyle(Style::Visible)) return;
    addStyle(TextField::Style::Center);
    bool erlaubt = hasStyle(Style::Allowed);
    bool rA = 0;
    if (!hasStyle(Style::Allowed))
    {
        zRObj.setAlpha(0x20);
        rA = 1;
    }
    bool tmpRend = rend;
    removeStyle(Style::VScroll | Style::HScroll | Style::Allowed);
    TextField::render(zRObj);
    if (!zRObj.setDrawOptions(innenPosition, innenSize))
    {
        if (rA) zRObj.releaseAlpha();
        setStyle(Style::Allowed, erlaubt);
        return;
    }
    if (hasStyle(Style::Visible) && klickIndex == 1)
    {
        if (hasStyle(Style::ClickColor))
        {
            if (hasStyle(Style::ClickAlpha))
                zRObj.alphaRegion(0, 0, innenSize.x, innenSize.y, klickColor);
            else
                zRObj.fillRegion(0, 0, innenSize.x, innenSize.y, klickColor);
        }
        if (hasStyle(Style::ClickImage) && clickImage)
        {
            if (hasStyle(Style::ClickAlpha))
                zRObj.alphaImage(0, 0, innenSize.x, innenSize.y, *clickImage);
            else
                zRObj.drawImage(0, 0, innenSize.x, innenSize.y, *clickImage);
        }
        if (hasStyle(Style::ClickBuffer) && klickBuffer)
        {
            klickBuffer->setSize(innenSize.x, innenSize.y);
            klickBuffer->render(zRObj);
        }
    }
    if (rA) zRObj.releaseAlpha();
    zRObj.releaseDrawOptions();
    setStyle(Style::Allowed, erlaubt);
    rend = tmpRend;
}

// constant
int Button::getClickColor() const // returns the click color
{
    return klickColor;
}

Image* Button::getClickImage() const // returns the click image
{
    if (!clickImage) return 0;
    return dynamic_cast<Image*>(clickImage->getThis());
}

Image* Button::zClickImage() const // returns a pointer to the click image
{
    return clickImage;
}

AlphaField* Button::getKB() const // returns the click buffer
{
    if (!klickBuffer) return 0;
    return dynamic_cast<AlphaField*>(klickBuffer->getThis());
}

AlphaField*
Button::zKB() const // returns the click buffer without reference counter
{
    return klickBuffer;
}

int Button::getKBColor() const // returns the click buffer color
{
    if (!klickBuffer) return 0;
    return klickBuffer->getColor();
}

int Button::getKBStrength() const // returns the click buffer strength
{
    if (!klickBuffer) return 0;
    return klickBuffer->getStrength();
}

Drawable*
Button::duplicate() const // creates a copy of the drawing and returns it
{
    Button* obj = new Button();
    obj->setPosition(pos);
    obj->setSize(gr);
    obj->setMouseEventParameter(makParam);
    obj->setKeyboardEventParameter(takParam);
    obj->setMouseEvent(mak);
    obj->setKeyboardEvent(tak);
    if (toolTip) obj->setToolTipZ((ToolTip*)toolTip->duplicate());
    obj->setStyle(style);
    obj->setFontSize(getFontSize());
    if (zFont()) obj->setFontZ(getFont());
    if (zText()) obj->setText(zText()->getText());
    obj->setBackgroundColor(backgroundColor);
    obj->setFontColor(getFontColor());
    if (backgroundFeld)
        obj->setAlphaFieldZ((AlphaField*)backgroundFeld->duplicate());
    if (border) obj->setBorderZ((Border*)border->duplicate());
    if (backgroundImage)
        obj->setBackgroundImage(
            dynamic_cast<Image*>(backgroundImage->getThis()));
    if (vertikalScrollBar)
    {
        obj->setVerticalClickScroll(vertikalScrollBar->getClickScroll());
        obj->setVerticalScrollPos(vertikalScrollBar->getScroll());
        obj->setVerticalScrollColor(
            vertikalScrollBar->getColor(), vertikalScrollBar->getBgColor());
    }
    if (horizontalScrollBar)
    {
        obj->setHorizontalClickScroll(horizontalScrollBar->getClickScroll());
        obj->setHorizontalScrollPos(horizontalScrollBar->getScroll());
        obj->setHorizontalScrollColor(
            horizontalScrollBar->getColor(), horizontalScrollBar->getBgColor());
    }
    obj->setSchowChar(getShowChar());
    // obj->setSelection( getSelectionPos(), getCursorPos() );
    obj->setClickColor(klickColor);
    if (clickImage)
        obj->setClickImage(dynamic_cast<Image*>(clickImage->getThis()));
    if (klickBuffer) obj->setKBZ((AlphaField*)klickBuffer->duplicate());
    return obj;
}

// Contents of the CheckBox class from Button.h
// Constructor
CheckBox::CheckBox()
    : DrawableBackground(),
      txt(0),
      sTxt(0),
      sBgF(0),
      kBgF(0),
      sBgB(0),
      kBgB(0),
      sAf(0),
      kAf(0),
      kasten(0),
      sKasten(0),
      textRd(0),
      sF(0xFFFFFFFF),
      sGr(12)
{
    style = Style::Allowed | Style::ClickBuffer;
    setClickAFColor(0x00007500);
    setClickAFStrength(-30);
}

// Destructor
CheckBox::~CheckBox()
{
    if (txt) txt->release();
    if (sTxt) sTxt->release();
    if (sBgB) sBgB->release();
    if (kBgB) kBgB->release();
    if (sAf) sAf->release();
    if (kAf) kAf->release();
    if (kasten) kasten->release();
    if (sKasten) sKasten->release();
    if (textRd) textRd->release();
}

void CheckBox::doMouseEvent(
    MouseEvent& me, bool userRet) // process mouse events
{
    if (me.id == ME_Leaves || !userRet) style &= ~Style::MouseClick;
    if (hasStyleNot(TextField::Style::Allowed) || !userRet) return;
    if (me.id == ME_Enter && hasStyle(Style::MouseClick) != MouseState[M_Left])
        setStyle(Style::MouseClick, MouseState[M_Left]);
    if (me.id == ME_PLeft) addStyle(Style::MouseClick);
    if (me.id == ME_RLeft)
    {
        removeStyle(Style::MouseClick);
        setStyle(Style::Selected, !hasStyle(Style::Selected));
    }
    me.processed = 1;
}

// non-constant
void CheckBox::setTextZ(Text* txt) // sets the text
{
    if (this->txt) this->txt->release();
    this->txt = txt;
    rend = 1;
}

void CheckBox::setText(Text* txt)
{
    if (!this->txt) this->txt = new Text();
    this->txt->setText(txt->getText());
    txt->release();
    rend = 1;
}

void CheckBox::setText(const char* txt)
{
    if (!this->txt) this->txt = new Text();
    this->txt->setText(txt);
    rend = 1;
}

void CheckBox::setSTextZ(Text* txt) // sets the text when selected
{
    if (sTxt) sTxt->release();
    sTxt = txt;
    rend = 1;
}

void CheckBox::setSText(Text* txt)
{
    if (!sTxt) sTxt = new Text();
    sTxt->setText(txt->getText());
    txt->release();
    rend = 1;
}

void CheckBox::setSText(const char* txt)
{
    if (!sTxt) sTxt = new Text();
    sTxt->setText(txt);
    rend = 1;
}

void CheckBox::setTextRendererZ(TextRenderer* textRd)
{
    if (this->textRd) this->textRd->release();
    this->textRd = textRd;
}

void CheckBox::setFontZ(Font* font) // sets the font
{
    if (!this->textRd)
        textRd = new TextRenderer(font);
    else
        textRd->setFontZ(font);
    rend = 1;
}

void CheckBox::setSColor(int f) // sets the font color
{
    sF = f;
    rend = 1;
}

void CheckBox::setSSize(int gr) // sets the font size
{
    sGr = gr;
    rend = 1;
}

void CheckBox::setSBgColor(int f) // sets the select background color
{
    sBgF = f;
    rend = 1;
}

void CheckBox::setClickBgColor(int f) // sets the click background color
{
    kBgF = f;
    rend = 1;
}

void CheckBox::setSBgImageZ(Image* b) // sets the select background image
{
    if (sBgB) sBgB->release();
    sBgB = b;
    rend = 1;
}

void CheckBox::setSBgImage(Image* b)
{
    if (!sBgB) sBgB = new Image();
    sBgB->newImage(b->getWidth(), b->getHeight(), 0);
    sBgB->drawImage(0, 0, b->getWidth(), b->getHeight(), *b);
    b->release();
    rend = 1;
}

void CheckBox::setClickBgImageZ(Image* b) // sets the click background image
{
    if (kBgB) kBgB->release();
    kBgB = b;
    rend = 1;
}

void CheckBox::setClickBgImage(Image* b)
{
    if (!kBgB) kBgB = new Image();
    kBgB->newImage(b->getWidth(), b->getHeight(), 0);
    kBgB->drawImage(0, 0, b->getWidth(), b->getHeight(), *b);
    b->release();
    rend = 1;
}

void CheckBox::setSAlphaFieldZ(AlphaField* af) // sets the select AlphaField
{
    if (sAf) sAf->release();
    sAf = af;
    rend = 1;
}

void CheckBox::setSAFColor(int f) // sets the select AlphaField color
{
    if (!sAf) sAf = new AlphaField();
    sAf->setColor(f);
    rend = 1;
}

void CheckBox::setSAFStrength(int st) // sets the select AlphaField strength
{
    if (!sAf) sAf = new AlphaField();
    sAf->setStrength(st);
    rend = 1;
}

void CheckBox::setClickAlphaFieldZ(AlphaField* af) // sets the click AlphaField
{
    if (kAf) kAf->release();
    kAf = af;
    rend = 1;
}

void CheckBox::setClickAFColor(int f) // sets the click AlphaField color
{
    if (!kAf) kAf = new AlphaField();
    kAf->setColor(f);
    rend = 1;
}

void CheckBox::setClickAFStrength(int st) // sets the click AlphaField strength
{
    if (!kAf) kAf = new AlphaField();
    kAf->setStrength(st);
    rend = 1;
}

void CheckBox::loadData(LTDBFile* dat) // loading the system images
{
    if (FileExists(new Text("data/normal.ltdb")) && (!dat || !dat->isOpen()))
    {
        LTDBFile* dat = new LTDBFile();
        dat->setFile(new Text("data/normal.ltdb"));
        dat->readData(0);
        kasten = dat->load(0, new Text("kasten.gif"));
        sKasten = dat->load(0, new Text("skasten.gif"));
        dat->release();
    }
    else
    {
        kasten = dat->load(0, new Text("kasten.gif"));
        sKasten = dat->load(0, new Text("skasten.gif"));
    }
    rend = 1;
}

void CheckBox::loadData(
    const char* ltdb) // loading the system images with a specified LTDB file
{
    if (FileExists(new Text(ltdb)))
    {
        LTDBFile* dat = new LTDBFile();
        dat->setFile(new Text(ltdb));
        dat->readData(0);
        kasten = dat->load(0, new Text("kasten.gif"));
        sKasten = dat->load(0, new Text("skasten.gif"));
        dat->release();
        rend = 1;
    }
}

void CheckBox::render(Image& zRObj) // renders into zRObj
{
    if (!hasStyle(Style::Visible)) return;
    removeStyle(Style::VScroll | Style::HScroll);
    DrawableBackground::render(zRObj);
    rwLock.lockRead();
    if (!zRObj.setDrawOptions(innenPosition, innenSize))
    {
        rwLock.unlockRead();
        return;
    }
    if (hasStyle(Style::MouseClick))
    {
        if (hasStyle(Style::ClickColor))
        {
            if (hasStyle(Style::ClickAlpha))
                zRObj.alphaRegion(0, 0, innenSize.x, innenSize.y, kBgF);
            else
                zRObj.fillRegion(0, 0, innenSize.x, innenSize.y, kBgF);
        }
        if (hasStyle(Style::ClickImage) && kBgB)
        {
            if (hasStyle(Style::ClickAlpha))
                zRObj.alphaImage(0, 0, innenSize.x, innenSize.y, *kBgB);
            else
                zRObj.drawImage(0, 0, innenSize.x, innenSize.y, *kBgB);
        }
        if (hasStyle(Style::ClickBuffer) && kAf)
        {
            kAf->setSize(innenSize.x, innenSize.y);
            kAf->render(zRObj);
        }
        int kbr = 0;
        if (hasStyle(Style::Selected) && sKasten)
        {
            if (sTxt && textRd)
                zRObj.drawImage(0,
                    (gr.y / 2 - sKasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - sKasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *sKasten);
            else
                zRObj.drawImage(gr.x / 2 - sKasten->getWidth() / 2,
                    (gr.y / 2 - sKasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - sKasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *sKasten);
            kbr = sKasten->getWidth();
            if (sTxt && textRd)
            {
                textRd->setFontSize(sGr);
                textRd->renderText(kbr + 5,
                    gr.y / 2 - textRd->getTextHeight(sTxt->getText()) / 2,
                    sTxt->getText(),
                    zRObj,
                    sF);
            }
        }
        else if (kasten)
        {
            if (txt && textRd)
                zRObj.drawImage(0,
                    (gr.y / 2 - kasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - kasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *kasten);
            else
                zRObj.drawImage(gr.x / 2 - kasten->getWidth() / 2,
                    (gr.y / 2 - kasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - kasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *kasten);
            kbr = kasten->getWidth();
            if (txt && textRd)
            {
                textRd->setFontSize(sGr);
                textRd->renderText(kbr + 5,
                    gr.y / 2 - textRd->getTextHeight(txt->getText()) / 2,
                    txt->getText(),
                    zRObj,
                    sF);
            }
        }
    }
    else if (hasStyle(Style::Selected))
    {
        if (hasStyle(Style::SelectColor))
        {
            if (hasStyle(Style::SelectAlpha))
                zRObj.alphaRegion(0, 0, innenSize.x, innenSize.y, sBgF);
            else
                zRObj.fillRegion(0, 0, innenSize.x, innenSize.y, sBgF);
        }
        if (hasStyle(Style::SelectImage) && sBgB)
        {
            if (hasStyle(Style::SelectAlpha))
                zRObj.alphaImage(0, 0, innenSize.x, innenSize.y, *sBgB);
            else
                zRObj.drawImage(0, 0, innenSize.x, innenSize.y, *sBgB);
        }
        if (hasStyle(Style::SelectBuffer) && sAf)
        {
            sAf->setSize(innenSize.x, innenSize.y);
            sAf->render(zRObj);
        }
        int kbr = 0;
        if (sKasten)
        {
            if (sTxt && textRd)
                zRObj.drawImage(0,
                    (gr.y / 2 - sKasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - sKasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *sKasten);
            else
                zRObj.drawImage(gr.x / 2 - sKasten->getWidth() / 2,
                    (gr.y / 2 - sKasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - sKasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *sKasten);
            kbr = sKasten->getWidth();
        }
        if (sTxt && textRd)
        {
            textRd->setFontSize(sGr);
            textRd->renderText(kbr + 5,
                gr.y / 2 - textRd->getTextHeight(sTxt->getText()) / 2,
                sTxt->getText(),
                zRObj,
                sF);
        }
    }
    else
    {
        int kbr = 0;
        if (kasten)
        {
            if (txt && textRd)
                zRObj.drawImage(0,
                    (gr.y / 2 - kasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - kasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *kasten);
            else
                zRObj.drawImage(gr.x / 2 - kasten->getWidth() / 2,
                    (gr.y / 2 - kasten->getHeight() / 2) < 0
                        ? 0
                        : (gr.y / 2 - kasten->getHeight() / 2),
                    innenSize.x,
                    innenSize.y,
                    *kasten);
            kbr = kasten->getWidth();
        }
        if (txt && textRd)
        {
            textRd->setFontSize(sGr);
            textRd->renderText(kbr + 5,
                gr.y / 2 - textRd->getTextHeight(txt->getText()) / 2,
                txt->getText(),
                zRObj,
                sF);
        }
    }
    zRObj.releaseDrawOptions();
    rwLock.unlockRead();
}

// constant
Text* CheckBox::getText() const // returns the text
{
    return txt ? dynamic_cast<Text*>(txt->getThis()) : 0;
}

Text* CheckBox::zText() const
{
    return txt;
}

Text* CheckBox::getSText() const // returns the select text
{
    return sTxt ? dynamic_cast<Text*>(sTxt->getThis()) : 0;
}

Text* CheckBox::zSText() const
{
    return sTxt;
}

Font* CheckBox::getFont() const // returns the font
{
    return textRd ? textRd->getFont() : 0;
}

Font* CheckBox::zFont() const
{
    return textRd ? textRd->zFont() : 0;
}

int CheckBox::getSColor() const // returns the font color
{
    return sF;
}

int CheckBox::getSSize() const // returns the font size
{
    return sGr;
}

int CheckBox::getSBgColor() const // returns the select background color
{
    return sBgF;
}

int CheckBox::getClickBgColor() const // returns the click background color
{
    return kBgF;
}

Image* CheckBox::getSBgImage() const // returns the select background image
{
    return sBgB ? dynamic_cast<Image*>(sBgB->getThis()) : 0;
}

Image* CheckBox::zSBgImage() const
{
    return sBgB;
}

Image* CheckBox::getClickBgImage() const // returns the click background image
{
    return kBgB ? dynamic_cast<Image*>(kBgB->getThis()) : 0;
}

Image* CheckBox::zClickBgImage() const
{
    return kBgB;
}

AlphaField* CheckBox::getSAlphaField() const // returns the select AlphaField
{
    return sAf ? dynamic_cast<AlphaField*>(sAf->getThis()) : 0;
}

AlphaField* CheckBox::zSAlphaField() const
{
    return sAf;
}

AlphaField* CheckBox::getClickAlphaField() const // returns the click AlphaField
{
    if (!kAf) return 0;
    return dynamic_cast<AlphaField*>(kAf->getThis());
}

AlphaField* CheckBox::zClickAlphaField() const
{
    return kAf;
}