/***************************************************************************
 *   Copyright (C) 2005 by Thierry CHARLES                                 *
 *   thierry@les-charles.net                                               *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "tcursor.h"
#include "tpoint.h"
#include "tcodeeditor.h"

#include "lib/lib_logging.h"
#include "lib/lib_string.h"

#include <iostream>


BEGIN_EVENT_TABLE(TCursor, wxEvtHandler)
        EVT_TIMER(_STDGUI_TCURSOR_CARET_TIMER_,TCursor::onCaretBlinkTimer)
END_EVENT_TABLE()


TCursor::TCursor(TCodeEditor * ed)
    : position(0,0), editor(ed), iRequestedXPos(0), iRequestedYPos(0)

{
    if(this->editor == NULL)
    {
        LOG_MESSAGE("editor is null : there will be no caret",logging::_FATAL_);
        return;
    }

    this->caret = new wxCaret(this->editor,2,this->editor->getLineHeight());
    this->caret->SetBlinkTime(300);
    this->editor->SetCaret(this->caret);
    this->caret->Show(true);

    this->caretBlinkTimer.SetOwner(this,_STDGUI_TCURSOR_CARET_TIMER_);
}

TCursor::~TCursor()
{
    this->caretBlinkTimer.Stop();
    this->setVisible(false);
    this->editor->SetCaret(NULL);
// on ne delete pas car autrement la lib wxWidgets fait une erreur de segmentation    delete this->caret;
}


void TCursor::setLine(int iLine)
{
    if(this->position.y != iLine)
    {
        this->position.y = iLine;
        this->fireCursorMoved();
    }
}

void TCursor::setColumn(int iColumn)
{
    if(this->position.x != iColumn)
    {
        this->position.x = iColumn;
        this->fireCursorMoved();
    }
}

void TCursor::setPosition(const TPoint & pt)
{
    if(this->position != pt)
    {
        this->position = pt;
        this->fireCursorMoved();
    }
}

void TCursor::updateCaret()
{
    if(!this->position.isValid())
        return;

    int iCursorHeight = this->editor->getLineHeight();
    int iCursorWidth = (this->editor->getTypeMode() == TCodeEditor::Insert) ? 2 : this->editor->getCharWidth();
    this->caret->SetSize(iCursorWidth,iCursorHeight);

    int iPosY = this->editor->getLineYPos(this->position.y);
    int iPosX = this->editor->getColumnXPos(this->position.y, this->position.x);
    this->caret->Move(iPosX,iPosY);
    this->iRequestedYPos = iPosY;
    this->iRequestedXPos = iPosX;
}

void TCursor::setVisible(bool bVisible)
{
    if(bVisible == this->caret->IsVisible())
        return;

    if(bVisible)
    {
        this->caret->Show();
        this->updateCaret();
    }
    else
    {
        this->caret->Hide();
    }
}

bool TCursor::isVisible()
{
    return this->caret->IsVisible();
}

int TCursor::getCursorPosX()
{
    return this->iRequestedXPos;
}

int TCursor::getCursorPosY()
{
    return this->iRequestedYPos;
}


bool TCursor::addCursorListener(TCursorListener * l)
{
    return this->listeners.insert(l).second;
}

bool TCursor::removeCursorListener(TCursorListener * l)
{
    return this->listeners.erase(l) != 0;
}

void TCursor::fireCursorMoved()
{
    this->updateCaret();

    if(this->caret->IsVisible())
    {
        this->caretBlinkTimer.Start(19,wxTIMER_ONE_SHOT); // continu pendant 2 secondes
        this->caret->SetBlinkTime(10);
    }

    TCursorListenersList::iterator itB = this->listeners.begin();
    TCursorListenersList::iterator itE = this->listeners.end();

    while(itB != itE)
    {
        (*itB)->cursorMoved(this);
        itB++;
    }
}

/** traite les evenements du timer de variation du blink */
void TCursor::onCaretBlinkTimer(wxTimerEvent& event)
{
    bool bShowCarret = this->caret->IsVisible();
    this->caret->Hide();
    this->caret->SetBlinkTime(300);
    this->caret->Show(bShowCarret);
}
