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

#include <QPainter>
#include <QPushButton>
#include <QGraphicsProxyWidget>

#include "switchdip.h"
#include "circuitwidget.h"
#include "itemlibrary.h"
#include "connector.h"
#include "simulator.h"
#include "circuit.h"
#include "e-node.h"
#include "pin.h"

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

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

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

LibraryItem* SwitchDip::libraryItem()
{
    return new LibraryItem(
        tr("Switch Dip"),
        "Switches",
        "switchdip.png",
        "SwitchDip",
        SwitchDip::construct); 
}

SwitchDip::SwitchDip( QString type, QString id )
         : Component( type, id )
         , eElement( id )
{
    m_graphical = true; 
    m_changed   = true; 

    m_commonPin = false; 
    m_exclusive = false; 

    m_color = QColor( 100, 100, 120 ); 
    m_size = 0; 
    m_state = 0; 
    setSize( 8 ); 
    setLabelPos(-16,-44, 0); 
    
    Simulator::self()->addToUpdateList( this ); 

    addPropGroup( { tr("Main"), {
        new IntProp <SwitchDip>("Size", tr("Size"), ""
                               , this, &SwitchDip::size, &SwitchDip::setSize, propNoCopy,"uint" ),

        new BoolProp<SwitchDip>("Exclusive", tr("Exclusive"), ""
                               , this, &SwitchDip::exclusive, &SwitchDip::setExclusive ),

        new BoolProp<SwitchDip>("CommonPin", tr("Common Pin"), ""
                               , this, &SwitchDip::commonPin, &SwitchDip::setCommonPin ),
    }, groupNoCopy } ); 

    addPropGroup( {"Hidden", {
new IntProp<SwitchDip>("State","","", this, &SwitchDip::state, &SwitchDip::setState,0,"uint" )
    }, groupHidden} ); 
}
SwitchDip::~SwitchDip(){}

void SwitchDip::stamp()
{
    eNode* node0 = m_pin[0]->getEnode(); 
    for( int i=0;  i<m_size;  i++ )
    {
        int pin1 = i*2; 
        int pin2 = pin1+1; 

        if( m_commonPin ) m_pin[pin1]->setEnode( node0 ); 
        else              node0 = m_pin[pin1]->getEnode(); 
        eNode* node1 = m_pin[pin2]->getEnode(); 

        //if( node0 ) node0->setSwitched( true ); 
        //if( node1 ) node1->setSwitched( true ); 

        m_pin[pin1]->setEnodeComp( node1 ); 
        m_pin[pin2]->setEnodeComp( node0 ); 
    }
    m_changed = true; 
    updateStep(); 
}

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

    int i = 0; 
    for( QPushButton* button : m_buttons )
    {
        bool   state = m_state & 1<<i; 
        double admit = 0; 

        if( state  ){
            button->setIcon( QIcon(":/switchbut.png") ); 
            admit = 1e3; 
        }else{
            button->setIcon( QIcon(":/stop.svg") ); 
        }
        button->setChecked( state ); 

        int pin = i*2; 
        m_pin[pin]->stampAdmitance( admit ); 
        m_pin[pin+1]->stampAdmitance( admit ); 

        i++; 
    }
}

void SwitchDip::onbuttonclicked()
{
    int i = 0; 
    for( QPushButton* button : m_buttons )
    {
        bool state = button->isChecked(); 
        if( m_exclusive )
        {
            if( state == (bool)(m_state & 1<<i) )
                state = false; 
        }

        if( state  )  m_state |= 1<<i; 
        else          m_state &= ~(1<<i); 

        i++; 
    }
    m_changed = true; 
    if( !Simulator::self()->isRunning() ) updateStep(); 
}

void SwitchDip::setState( int state )
{
    if( m_state == state ) return; 
    m_state = state; 

    for( QPushButton* button : m_buttons )
    {
        bool switchState = state&1; 
        state >>= 1; 
        
        button->setChecked( switchState ); 
        
        if( switchState  ) button->setIcon(QIcon(":/switchbut.png")); 
        else               button->setIcon(QIcon(":/stop.svg")); 
    }
    m_changed = true; 
    if( !Simulator::self()->isRunning() ) updateStep(); 
}

void SwitchDip::createSwitches( int c )
{
    int start = m_size; 
    m_size = m_size+c; 
    m_pin.resize( m_size*2 ); 

    for( int i=start;  i<m_size;  i++ )
    {
        int index = i*2; 
        QString butId = m_id + QString("-switch"+QString::number(i)); 
        QPushButton* button = new QPushButton( ); 
        button->setMaximumSize( 6, 6 ); 
        button->setGeometry(-6,-6, 6, 6); 

        button->setCursor( Qt::PointingHandCursor ); 
        button->setCheckable( true ); 
        button->setChecked( true ); 
        button->setIcon(QIcon(":/switchbut.png")); 
        m_buttons.append( button ); 
        
        QGraphicsProxyWidget* proxy = Circuit::self()->addWidget( button ); 
        proxy->setParentItem( this ); 
        proxy->setPos( QPoint( 3,-27+i*8 ) ); 
        m_proxys.append( proxy ); 
        QObject::connect( button, &QPushButton::released, [=](){ onbuttonclicked();  }); 

        Pin* pin = new Pin( 180, QPoint(-8,-32+8+i*8 ), butId+"-pinP", 0, this, 5 ); 
        pin->setVisible( !m_commonPin ); 
        m_pin[index] = pin; 

        pin = new Pin( 0, QPoint( 16,-32+8+i*8 ), butId+"-pinN", 0, this, 5 ); 
        m_pin[index+1] = pin; 
        
        m_state |= 1<<i;                           // default state = on; 
}   }

void SwitchDip::deleteSwitches( 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_buttons.takeLast(); 
        m_proxys.removeLast(); 
    }
    m_size = m_size-d; 
    m_pin.resize( m_size*2 ); 
    
    Circuit::self()->update(); 
}

void SwitchDip::setSize( int size )
{
    if( size < 1 ) size = 1; 
    if( m_size == size ) return; 

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

    if     ( size < m_size ) deleteSwitches( m_size-size ); 
    else if( size > m_size ) createSwitches( size-m_size ); 
    
    m_area = QRectF(-3,-28, 14, m_size*8 ); 

    Circuit::self()->update(); 
}

void SwitchDip::setExclusive( bool e )
{
    if( m_exclusive == e ) return; 
    m_exclusive = e; 
    if( e ) m_state = 0; 
    m_changed = true; 
    if( !Simulator::self()->isRunning() ) updateStep(); 
}

void SwitchDip::setCommonPin( bool c )
{
    if( m_commonPin == c ) return; 
    m_commonPin = c; 

    for( int i=2;  i<m_size*2;  i+=2 )
    {
        if( c ) m_pin[i]->removeConnector(); 
        m_pin[i]->setVisible( !c ); 
    }
}

void SwitchDip::setHidden( bool hid, bool hidArea, bool hidLabel )
{
    Component::setHidden( hid, hidArea, hidLabel ); 
    { for( int i=2;  i<m_size*2;  i+=2 )  m_pin[i]->setVisible( !m_commonPin && !hid );  }
}

void SwitchDip::setLinkedValue( double v, int i )
{
    if( i == 0 ) { int p = v;  m_state = 1<<p;  }
    else         m_state = v; 
    m_changed = true; 
}

void SwitchDip::remove()
{
    deleteSwitches( m_size ); 
    Component::remove(); 
}

void SwitchDip::paint( QPainter* p, const QStyleOptionGraphicsItem* o, QWidget* w )
{
    Component::paint( p, o, w ); 
    p->drawRect( m_area ); 

    Component::paintSelected( p ); 
}
