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

#include "resistordip.h"
#include "circuitwidget.h"
#include "itemlibrary.h"
#include "connector.h"
#include "simulator.h"
#include "circuit.h"
#include "pin.h"
#include "resistor.h"
#include "e-resistor.h"
#include "label.h"
#include "propdialog.h"
#include "mainwindow.h"

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

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

eNode ResistorDip::m_puEnode("");

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

LibraryItem* ResistorDip::libraryItem()
{
    return new LibraryItem(
        tr("ResistorDip"),
        "Resistors",
        "resistordip.png",
        "ResistorDip",
        ResistorDip::construct);
}

ResistorDip::ResistorDip( QString type, QString id )
           : Component( type, id )
           , eElement( id )
{
    m_pullUp = false;
    m_puVolt = 5;

    m_size = 0;
    setSize( 8 );

    setLabelPos(-24,-40, 0);
    //setValLabelPos( 4,-26, 90 );
    //m_valLabel->setAcceptedMouseButtons( 0 );

    //QFont font = m_valLabel->font();
    //font.setPixelSize( 6 );
    //m_valLabel->setFont( font );

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

    addPropGroup( { tr("Main"), {
        new DoubProp<ResistorDip>("Resistance", tr("Resistance"), "Ω"
                                 , this, &ResistorDip::resistance, &ResistorDip::setResistance ),

        new IntProp <ResistorDip>("Size", tr("Size"), ""
                                 , this, &ResistorDip::size, &ResistorDip::setSize, propNoCopy,"uint" ),

        new BoolProp<ResistorDip>("PullUp", tr("Pullup"), ""
                                 , this, &ResistorDip::pullUp, &ResistorDip::setPullUp ),

        new DoubProp<ResistorDip>("PuVolt", tr("Pullup Voltage"), "V"
                                 , this, &ResistorDip::puVolt, &ResistorDip::setPuVolt ),
    },0 } );

    setShowProp("Resistance");
    setPropStr( "Resistance", "100" );
}
ResistorDip::~ResistorDip(){}

void ResistorDip::stamp()
{
    if( !m_pullUp ) return;
    m_puEnode.setVolt( m_puVolt );
    for( int i=0; i<m_size; i++ )
    {
        int index = i*2;
        m_pin[index+1]->setEnode( &m_puEnode );
        m_pin[index]->createCurrent();
        m_pin[index]->stampCurrent( m_puVolt/m_resistance );
    }
}

void ResistorDip::updateStep()
{
    if( !m_changed ) return;
    m_changed = false;

    for( eResistor* res : m_resistor ) res->setResistance( m_resistance );
    stamp();
}

void ResistorDip::createResistors( int c )
{
    int start = m_size;
    m_size = m_size+c;
    m_resistor.resize( m_size );
    m_pin.resize( m_size*2 );

    for( int i=start; i<m_size; i++ )
    {
        int index = i*2;
        QString reid = m_id;
        reid.append(QString("-resistor"+QString::number(i)));
        m_resistor[i] = new eResistor( reid );
        m_resistor[i]->setResistance( m_resistance );

        m_pin[index] = new Pin( 180, QPoint(-16,-32+8+i*8 ), reid+"-ePin"+QString::number(index), 0, this);
        m_resistor[i]->setEpin( 0, m_pin[index] );

        m_pin[index+1] = new Pin( 0, QPoint( 16,-32+8+i*8 ), reid+"-ePin"+QString::number(index+1), 0, this);
        m_pin[index+1]->setEnabled( !m_pullUp ); //
        m_pin[index+1]->setVisible( !m_pullUp ); //
        m_resistor[i]->setEpin( 1, m_pin[index+1] );
}   }

void ResistorDip::deleteResistors( int d )
{
    if( d > m_size ) d = m_size;
    int start = m_size-d;

    for( int i=start*2; i<m_size*2; ++i ) deletePin( m_pin[i] );
    for( int i=start;   i<m_size;   ++i ) delete m_resistor[i];
    m_size = m_size-d;
    m_resistor.resize( m_size );
    m_pin.resize( m_size*2 );
}

void ResistorDip::setResistance( double resist )
{
    if( resist < 1e-12 ) resist = 1e-12;
    if( m_resistance == resist ) return;
    m_resistance = resist;
    m_changed = true;
    if( !Simulator::self()->isRunning() ) updateStep();
}

void ResistorDip::setSize( int size )
{
    if( size == m_size || size < 1 ) return;
    if( Simulator::self()->isRunning() )  CircuitWidget::self()->powerCircOff();

    if     ( size < m_size ) deleteResistors( m_size-size );
    else if( size > m_size ) createResistors( size-m_size );
    
    m_area = QRect( -10, -30, 20, m_size*8+4 );
    Circuit::self()->update();
}

void ResistorDip::setPullUp( bool p )
{
    if( m_pullUp == p ) return;
    m_pullUp = p;

    if( Simulator::self()->isRunning() )  CircuitWidget::self()->powerCircOff();

    updtProperties();

    for( int i=0; i<m_size; i++ )
    {
        int index = i*2+1;
        m_pin[index]->setEnabled( !p );
        m_pin[index]->setVisible( !p );
        if( p ) m_pin[index]->removeConnector();
        else    m_pin[index]->setEnode( nullptr );
    }
    update();
}

void ResistorDip::updtProperties()
{
    if( !m_propDialog ) return;
    m_propDialog->showProp("PuVolt", m_pullUp );
    m_propDialog->adjustWidgets();
}

void ResistorDip::slotProperties()
{
    Component::slotProperties();
    updtProperties();
}

void ResistorDip::remove()
{
    deleteResistors( m_size );
    Component::remove();
}

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

    if( m_ansiSymbol ){
        for( int i=0; i<m_size; i++ ) Resistor::drawAnsi( p, 0,-32+8+i*8, 0.7, 0.6 );
    }
    else p->drawRect( QRect(-9,-28, 18, m_size*8 ) );

    if( m_pullUp )
    {
        p->setRenderHint( QPainter::Antialiasing, true );
        QPen pen( Qt::black, 0.1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
        p->setPen( pen );
        if( m_puVolt > 2.5 ){
            p->setBrush( QColor( 200, 50, 50 ) );
            p->drawRoundedRect( 3,-26, 4, 4, 2, 2 );
        }else{
            p->setBrush( QColor( 50,  50, 200 ) );
            p->drawRoundedRect(-7,-26, 4, 4, 2, 2 );
        }
    }

    Component::paintSelected( p );
}
