/***************************************************************************
 *   Copyright (C) 2017 by Santiago González                               *
 *                                                                         *
 ***( see copyright.txt file at root folder )*******************************/

#include <QCursor>
#include <QPainter>
#include <QTextDocument>
#include <QGuiApplication>

#include "textcomponent.h"
#include "itemlibrary.h"
#include "circuit.h"
#include "simulator.h"
#include "circuit.h"
#include "circuitwidget.h"

#include "stringprop.h"
#include "doubleprop.h"
#include "boolprop.h"
#include "intprop.h"

#define tr(str) simulideTr("TextComponent",str)

Component* TextComponent::construct( QString type, QString id )
{ return new TextComponent( type, id );  }

LibraryItem* TextComponent::libraryItem()
{
    return new LibraryItem(
        tr("Text"),
        "Graphical",
        "text.png",
        "TextComponent",
        TextComponent::construct ); 
}

TextComponent::TextComponent( QString type, QString id )
             : LinkerComponent( type, id )
{
    m_graphical = true; 
    m_changed   = false; 
    m_opac = 1; 
    m_color = QColor( 255, 255, 220 ); 
    m_font  = "Helvetica [Cronyx]"; 

    QFont sansFont( m_font, 10 ); 
    #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
    sansFont.setWeight( QFont::Medium ); 
    #else
    sansFont.setWeight( QFont::Normal ); 
    #endif
    sansFont.setFixedPitch(true); 

    QColor color = Qt::darkBlue; 
    m_fontColor = color.name(); 
    m_text = new QGraphicsTextItem( this ); 
    m_text->setTextInteractionFlags( Qt::NoTextInteraction ); 
    m_text->setTextWidth( 90 ); 
    m_text->setFont( sansFont ); 
    m_textString = "... TEXT ..."; 
    m_text->setPlainText( m_textString ); 
    m_text->setPos( 0, 0 ); 
    m_text->document()->setTextWidth(-1); 
    m_text->setDefaultTextColor( color ); 
    m_text->setCursor( Qt::OpenHandCursor ); 
    //m_text->installEventFilter( this ); 

    m_margin = 5; 
    m_docMargin = m_text->document()->documentMargin(); 
    m_context = false; 
    m_border = 1; 
    updateGeometry( 0, 0, 0 ); 
    
    setFontSize( 10 ); 

    Simulator::self()->addToUpdateList( this ); 

    QObject::connect( m_text->document(), &QTextDocument::contentsChange
                    , [=](int f, int cr, int ca){ updateGeometry(f,cr,ca);  } ); 

    addPropGroup( { tr("Main"), {
        new IntProp <TextComponent>("Margin", tr("Margin"),"_px"
                                   , this, &TextComponent::margin, &TextComponent::setMargin ),

        new IntProp <TextComponent>("Border", tr("Border"),"_px"
                                   , this, &TextComponent::border, &TextComponent::setBorder,0,"uint" ),

        new StrProp <TextComponent>("Color", tr("Background Color"),""
                                   , this, &TextComponent::colorStr,&TextComponent::setColorStr,0,"color" ),

        new DoubProp<TextComponent>("Opacity", tr("Opacity"),""
                                   , this, &TextComponent::opac, &TextComponent::setOpac )
    }, groupNoCopy} ); 

    addPropGroup( { tr("Text"), {
        new StrProp <TextComponent>("Font", tr("Font"),""
                                   , this, &TextComponent::getFont , &TextComponent::setFont ),

        new StrProp <TextComponent>("Font_Color", tr("Font Color"),""
                                   , this, &TextComponent::fontColor, &TextComponent::setFontColor,0,"color" ),

        new IntProp <TextComponent>("Font_Size", tr("Font Size") ,"_px"
                                   , this, &TextComponent::fontSize , &TextComponent::setFontSize ),

        new BoolProp<TextComponent>("Fixed_Width", tr("Fixed_Width"),""
                                   , this, &TextComponent::fixedW, &TextComponent::setFixedW ),

        new StrProp <TextComponent>("Text", tr("Text"),""
                                   , this, &TextComponent::getText, &TextComponent::setText,0,"textEdit" )
    }, groupNoCopy} ); 
}
TextComponent::~TextComponent()
{
    delete m_text; 
}

void TextComponent::updateStep()
{
    if( !m_changed && m_linkedComp.isEmpty() ) return; 
    m_changed = false; 

    QString text = m_textString; 

    for( int i=0;  i<m_linkedComp.size();  ++i )
    {
        Component* comp = m_linkedComp.at( i ); 
        comp->update(); 
        QString data = comp->getValLabelText(); 
        text.replace( "$data"+QString::number(i), data ); 
    }
    m_text->document()->setPlainText( text ); 
}

void TextComponent::updateGeometry(int, int, int)
{
    m_text->document()->setTextWidth(-1); 
    
    int margin = m_margin; 
    if( margin < 0 ) margin = 0; 
    m_area = QRect(-margin,-margin, m_text->boundingRect().width()+margin*2, m_text->boundingRect().height()+margin*2 ); 
    
    Circuit::self()->update(); 
}

int TextComponent::margin() { return m_margin;  }

void TextComponent::setMargin( int margin )
{
    // Maintain compatibility with older versions:
    if( margin < 0 ) m_text->document()->setDocumentMargin( m_docMargin+margin ); 
    else             m_text->document()->setDocumentMargin( m_docMargin ); 
    m_margin = margin; 
    updateGeometry( 0, 0, 0 ); 
}

void TextComponent::setColorStr( QString color )
{
    m_color = QColor( color); 
    update(); 
}

void TextComponent::setOpac( qreal op )
{
    if     ( op > 1 ) op = 1; 
    else if( op < 0 ) op = 0; 
    m_opac = op; 
    update(); 
}

void TextComponent::setFont( QString font )
{
    if( font == "" ) return; 
    m_font = font; 

    QFont Tfont = m_text->font(); 
    Tfont.setFamily( font ); 
    m_text->setFont( Tfont ); 
    updateGeometry( 0, 0, 0 ); 
}

void TextComponent::setFontSize( int size )
{
    if( size < 1 ) return; 
    m_fontSize = size; 

    QFont font = m_text->font(); 
    font.setPixelSize( size ); 
    m_text->setFont( font ); 
    updateGeometry( 0, 0, 0 ); 
}

void TextComponent::setFontColor( QString color )
{
    m_fontColor = color; 
    m_text->setDefaultTextColor( QColor( color) ); 
    update(); 
}

void TextComponent::setFixedW( bool fixedW ) 
{ 
    m_fixedW = fixedW; 
    
    QFont font = m_text->font(); 
    font.setFixedPitch( fixedW ); 
    m_text->setFont( font ); 
    updateGeometry( 0, 0, 0 ); 
}

QString TextComponent::getText()
{
    QString text = m_textString; 
    return text.replace("\n", "&#xa; ").replace("\"", "&#x22; ")
            .replace("=", "&#x3D").replace("<", "&#x3C").replace(">", "&#x3E"); 
}

void TextComponent::setText( QString text )
{
    m_textString = text.replace("&#xa; ", "\n").replace("&#x22; ", "\"")
            .replace("&#x3D", "=").replace("&#x3C", "<").replace("&#x3E", ">"); 
    m_changed = true; 
    if( !Simulator::self()->isRunning() ) updateStep(); 
}

void TextComponent::createLinks( QList<Component*>* compList )
{
    m_changed = true; 
    Linker::createLinks( compList ); 
    if( !Simulator::self()->isRunning() ) updateStep(); 
}

void TextComponent::compSelected( Component* comp )
{
    m_changed = true; 
    Linker::compSelected( comp ); 
    if( !Simulator::self()->isRunning() ) updateStep(); 
}

void TextComponent::setLinkedString( QString str, int i )
{
    if( i == 0 ) setText( str ); 
    else         setText( m_textString+str ); 
}

void TextComponent::setLinkedValue( double v, int i )
{
    QString str = QString::number( v ); 

    if( i == 0 ) setText( str ); 
    else         setText( m_textString+"/n"+str ); 
}

void TextComponent::paint( QPainter* p, const QStyleOptionGraphicsItem* o, QWidget* w )
{
    Component::paint( p, o, w ); 

    QPen pen( Qt::black, m_border, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); 
    p->setPen( pen ); 

    double opacity = p->opacity(); 
    p->setOpacity( opacity*m_opac ); 
    p->drawRect( m_area ); 
    p->setOpacity( opacity ); 

    if( m_border > 0 )
    {
        p->setBrush( Qt::transparent ); 
        p->drawRect( m_area ); 
    }
    Component::paintSelected( p ); 
}
