/* guielement.cc
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2001-2021 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "guielement.h"
#include "awindow.h"
#include "bubblewindow.hh"

const char *GUIElement::type="GUIElement";

GUIElement::GUIElement(AGUIX *taguix) : Widget( taguix )
{
  _x = 0;
  _y = 0;
  _w = 1;
  _h = 1;
  win=0;
  visible = false;
  cb = NULL;
  sendMsg = true;
}

GUIElement::~GUIElement()
{
    _aguix->clearBubbleHelpCandidate( this );

    if ( auto bw = m_bubble_help_window.lock() ) {
        bw->hide();
        bw->unsetLinkedWidget();
        _aguix->setBubbleHelpWindow( nullptr );
    }

    destroy();
}

void GUIElement::move(int tx,int ty)
{
  _x = tx;
  _y = ty;
  if ( isCreated() == true ) {
    _parent->moveSubWin(win,tx,ty);
    //redraw();
  }
}

void GUIElement::resize(int tw,int th)
{
  if((tw<1)||(th<1)) return;
  _w = tw;
  _h = th;
  if ( isCreated() == true ) {
    _parent->resizeSubWin(win,tw,th);
    redraw();
  }
}

void GUIElement::redraw()
{
}

void GUIElement::flush()
{
}

const char *GUIElement::getType() const
{
  return type;
}

bool GUIElement::isType(const char *qtype) const
{
  if(strcmp(type,qtype)==0) return true;
  return false;
}

bool GUIElement::handleMessage(XEvent *E,Message *msg)
{
    // true falls die Message interessiert
    // false wenn nicht

    if ( ! m_bubble_help_text.empty() || m_bubble_help_cb ) {
        if ( msg->type == EnterNotify &&
             isParent( msg->window ) ) {
            _aguix->setBubbleHelpCandidate( this );
        }
    }

    return false;
}

void GUIElement::getPos(int *tx,int *ty) const
{
  if ( tx != NULL ) *tx = _x;
  if ( ty != NULL ) *ty = _y;
}

void GUIElement::getSize(int *tw,int *th) const
{
  if ( tw != NULL ) *tw = _w;
  if ( th != NULL ) *th = _h;
}

bool GUIElement::hasWin(Window twin) const
{
  if ( isCreated() == true ) {
    if(this->win==twin) return true;
  }
  return false;
}

Window GUIElement::getWindow() const
{
  return win;
}

void GUIElement::toBack()
{
  if ( isCreated() == false ) return;
  _aguix->WindowtoBack(win);
}

void GUIElement::toFront()
{
  if ( isCreated() == false ) return;
  _aguix->WindowtoFront(win);
}

bool GUIElement::isParent(Window twin) const
{
  if ( isCreated() == true ) {
    if(this->win==twin) return true;
  }
  return false;
}

void GUIElement::paste( const unsigned char *content )
{
}

void GUIElement::cancelpaste()
{
}

void GUIElement::cancelcut()
{
}

void GUIElement::takeFocus()
{
  if ( ( _parent != NULL ) && ( getAcceptFocus() == true ) ) {
    _parent->applyFocus( this );
    redraw();
  }
}

void GUIElement::hide()
{
  if ( isCreated() == true ) {
    if ( visible == true ) {
      _parent->hide( win );
      visible = false;
    }
  }
}

void GUIElement::show()
{
  if ( isCreated() == true ) {
    if ( visible == false ) {
      _parent->show( win );
      visible = true;
    }
  }
}

void GUIElement::doCreateStuff()
{
  if ( win == 0 ) {
    win = _parent->getSubWindow( 0, _x, _y, _w, _h );
    visible = true;
    Widget::doCreateStuff();
  }
}

void GUIElement::doDestroyStuff()
{
  if ( win != 0 ) {
    _parent->removeSubWin( win );
    win = 0;
    visible = false;
    Widget::doDestroyStuff();
  }
}

bool GUIElement::isVisible() const
{
  if ( visible == false ) return false;
  else {
    if ( _parent != NULL ) {
      if ( _parent->isVisible() == true ) return true;
      else return false;
    } else {
      return false;
    }
  }
}

void GUIElement::connect( CallBack *new_cb )
{
  cb = new_cb;
  setSendMessage( false );
}

void GUIElement::setSendMessage( bool nv )
{
  sendMsg = nv;
}

bool GUIElement::getSendMessage() const
{
  return sendMsg;
}

int GUIElement::msgAndCB( std::unique_ptr<AGMessage> msg )
{
    AGMessage *agmsg = msg.release();
    if ( agmsg == NULL ) return 1;

    _aguix->executeAfterMsgHandler( [ this, agmsg ] {
        if ( cb != NULL ) {
            if ( _parent != NULL && _parent->callBackForbidden() == false ) {
                _parent->forbidCallBacks();
                cb->run( this, *agmsg );
                _parent->permitCallBacks();
            }
        }
        if ( sendMsg == true ) {
            _aguix->putAGMsg( agmsg );
        } else {
            _aguix->ReplyMessage( agmsg );
        }
    });

    return 0;
}

int GUIElement::callback( int val )
{
    _aguix->executeAfterMsgHandler( [ this, val ] {
        if ( cb != NULL ) {
            if ( _parent != NULL && _parent->callBackForbidden() == false ) {
                _parent->forbidCallBacks();
                cb->run_int( this, val );
                _parent->permitCallBacks();
            }
        }
    });

    return 0;
}

void GUIElement::setBubbleHelpText( const std::string &help_text )
{
    m_bubble_help_text = help_text;
}

void GUIElement::openBubbleHelp()
{
    std::string text;

    if ( ! m_bubble_help_text.empty() ) {
        text = m_bubble_help_text;
    } else if ( m_bubble_help_cb ) {
        text = m_bubble_help_cb( m_bubble_help_cb_int_data );
    }

    if ( ! text.empty() ) {
        auto sp = std::make_shared< BubbleWindow >( _aguix, 10, 10, 50, 50, "", this );

        m_bubble_help_window = sp;

        sp->prepareHelpText( text );
        sp->show();

        _aguix->setBubbleHelpWindow( sp );
    }
}

void GUIElement::setBubbleHelpCallback( std::function< std::string( int data ) > cb, int data )
{
    m_bubble_help_cb = cb;
    m_bubble_help_cb_int_data = data;
}
