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

#include "sevensegment.h"
#include "circuitwidget.h"
#include "itemlibrary.h"
#include "connector.h"
#include "simulator.h"
#include "circuit.h"
#include "pin.h"

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

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

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

LibraryItem* SevenSegment::libraryItem()
{
    return new LibraryItem(
        tr("7 Segment"),
        "Leds",
        "seven_segment.png",
        "Seven Segment",
        SevenSegment::construct );
}

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

    setLabelPos( 20,-44, 0 );

    m_color = QColor(0,0,0);
    setColorStr("Yellow");

    m_commonCathode = true;
    m_verticalPins  = false;
    m_numDisplays = 0;
    m_threshold  = 2.4;
    m_maxCurrent = 0.02;
    m_resistance = 1;

    m_ePin.resize(8);
    m_pin.resize(8);

    QString pinid;
    for( int i=0; i<7; ++i ) // Create Pins for 7 segments
    {
        pinid = m_id+"-pin_"+QChar( 97+i ); // a..g
        m_ePin[i] = m_pin[i] = new Pin( 180, QPoint(-16-8,-24+i*8 ), pinid, 0, this );
        m_pin[i]->setSpace( 1 );
        m_pin[i]->setLength( 6 );
        m_pin[i]->setFontSize( 4 );
        m_pin[i]->setLabelText( QChar('a'+i) );
    }
    // Pin dot
    m_ePin[7] = m_pin[7] = new Pin( 270, QPoint( -8, 24+8 ), m_id+"-pin_dot", 0, this );
    m_pin[7]->setSpace( 1 );
    m_pin[7]->setLength( 4 );
    m_pin[7]->setFontSize( 4 );
    m_pin[7]->setLabelText( "." );

    setNumDisplays( 1 );

    addPropGroup( { tr("Main"), {
        new StrProp <SevenSegment>("Color", tr("Color"), LedBase::getColorList()
                                  , this, &SevenSegment::colorStr, &SevenSegment::setColorStr,0,"enum" ),

        new IntProp <SevenSegment>("NumDisplays"  , tr("Size"), ""
                                  , this, &SevenSegment::numDisplays, &SevenSegment::setNumDisplays, propNoCopy ),

        new BoolProp<SevenSegment>("Vertical_Pins", tr("Vertical Pins"), ""
                                  , this, &SevenSegment::verticalPins, &SevenSegment::setVerticalPins, propNoCopy )
            }, 0} );

    addPropGroup( { tr("Electric"), {
        new BoolProp<SevenSegment>("CommonCathode", tr("Common Cathode"), ""
                                  , this, &SevenSegment::isComCathode, &SevenSegment::setComCathode, propNoCopy ),

        new DoubProp<SevenSegment>("Threshold" , tr("Forward Voltage"),"V"
                                  , this, &SevenSegment::threshold, &SevenSegment::setThreshold ),

        new DoubProp<SevenSegment>("MaxCurrent", tr("Max Current"),"A"
                                  , this, &SevenSegment::maxCurrent, &SevenSegment::setMaxCurrent ),

        new DoubProp<SevenSegment>("Resistance", tr("Resistance"),"Ω"
                                  , this, &SevenSegment::resistance, &SevenSegment::setResistance ),
    },0} );
}
SevenSegment::~SevenSegment() { }

void SevenSegment::stamp()
{
    for( int i=0; i<8; ++i ) m_enode[i] = m_ePin[i]->getEnode(); // Get eNode of pin i
    for( int i=0; i<m_numDisplays; ++i )
    {
        eNode* commonEnode = m_commonPin[i]->getEnode();     // Get eNode of common

        int pin;
        for( int j=0; j<8; ++j )
        {
            pin = i*8+j;
            if( m_commonCathode )
            {
                m_cathodePin[pin]->setEnode( commonEnode );
                m_anodePin[pin]->setEnode( m_enode[j] );
            }else{
                m_anodePin[pin]->setEnode( commonEnode );
                m_cathodePin[pin]->setEnode( m_enode[j] );
}   }   }   }

QString SevenSegment::colorStr()
{
    if( m_segment[0] ) return m_segment[0]->colorStr();
    else               return "Yellow";
}

void SevenSegment::setColorStr( QString color )
{
    for( LedSmd* segment : m_segment ) segment->setColorStr( color );
    if( m_showVal && (m_showProperty == "Color") )
        setValLabelText( color );
}

void SevenSegment::setNumDisplays( int displays )
{
    if( displays < 1 ) displays = 1;
    if( displays == m_numDisplays ) return;

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

    m_area = QRect(-18,-24-4, 32*displays+4, 48+8 );

    if( displays > m_numDisplays )
    {
        resizeData( displays );
        for( int i=m_numDisplays; i<displays; ++i ) createDisplay( i );
    }else{
        for( int i=displays; i<m_numDisplays; ++i ) deleteDisplay( i );
        resizeData( displays );
    }
    m_numDisplays = displays;
    setResistance( m_resistance );
    setThreshold( m_threshold );
    setMaxCurrent( m_maxCurrent );

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

void SevenSegment::resizeData( int displays )
{
    m_pin.resize( 8+displays );
    m_commonPin.resize( displays );
    m_cathodePin.resize( displays*8 );
    m_anodePin.resize( displays*8 );
    m_segment.resize( displays*8 );
}

void SevenSegment::setComCathode( bool isCommonCathode )
{
    if( Simulator::self()->isRunning() )  CircuitWidget::self()->powerCircOff();
    m_commonCathode = isCommonCathode;
    QString label = m_commonCathode ? "|" : "+";
    for( int i=0; i<m_numDisplays; ++i ) m_commonPin[i]->setLabelText( label );
}

void SevenSegment::setVerticalPins( bool v )
{
    if( v == m_verticalPins ) return;
    m_verticalPins = v;
    
    if( v ) {
        for( int i=0; i<5; ++i ){
            m_pin[i]->setPos(-16+8*i,-24-8 );
            m_pin[i]->setLength( 4 );
            m_pin[i]->setPinAngle( 90 );
            m_pin[i]->isMoved();
        }
        for( int i=5; i<8; ++i ){
            m_pin[i]->setPos(-16+8*(i-5), 24+8 );
            m_pin[i]->setLength( 4 );
            m_pin[i]->setPinAngle( 270 );
            m_pin[i]->isMoved();
        }
    }else{
        for( int i=0; i<7; ++i ){
            m_pin[i]->setPos(-16-8,-24+i*8 );
            m_pin[i]->setLength( 6 );
            m_pin[i]->setPinAngle( 180 );
            m_pin[i]->isMoved();
        }
        m_pin[7]->setPos(-8, 24+8 );
        m_pin[7]->setRotation( 270 );
        m_pin[7]->isMoved();
    }
    m_area = QRect(-18,-24-4, 32*m_numDisplays+4, 48+8 );

    Circuit::self()->update();
}
        
void SevenSegment::setResistance( double res )
{
    if( res < 1e-6 ) res = 1;
    m_resistance = res;
    for( uint i=0; i<m_segment.size(); ++i ) m_segment[i]->setResistance( res );
}

void SevenSegment::setThreshold( double threshold )
{
    if( threshold < 1e-6 ) threshold = 2.4;
    m_threshold = threshold;
    for( uint i=0; i<m_segment.size(); ++i ) m_segment[i]->setThreshold( threshold );
}

void SevenSegment::setMaxCurrent( double current )
{
    if( current < 1e-6 ) current = 0.02;
    m_maxCurrent = current;
    for( uint i=0; i<m_segment.size(); ++i ) m_segment[i]->setMaxCurrent( current );
}

void SevenSegment::deleteDisplay(int n )
{
    deletePin( m_commonPin[n] );
    for( int i=0; i<8; ++i ) delete m_segment[n*8+i];
}

void SevenSegment::createDisplay( int n )
{
    int x = 32*n;

    // Pin common
    QString label = m_commonCathode ? "|" : "+";
    QString pinid = m_id+"-pin_common"+QChar( 97+n );
    m_commonPin[n] = m_pin[8+n]= new Pin( 270, QPoint( x+8, 24+8 ), pinid, 0, this );
    m_commonPin[n]->setLength( 4 );
    m_commonPin[n]->setSpace( 1 );
    m_commonPin[n]->setFontSize( 4 );
    m_commonPin[n]->setLabelText( label );

    for( int i=0; i<8; ++i ) // Create segments
    {
        pinid = m_id+"-led_"+QChar( 97+i );
        LedSmd* lsmd;
        if( i<7 ) lsmd = new LedSmd( "LEDSMD", pinid, QRectF(0, 0, 13.5, 1.5) ); // Segment
        else      lsmd = new LedSmd( "LEDSMD", pinid, QRectF(0, 0, 1.5, 1.5) );  // Point

        lsmd->setParentItem(this);
        lsmd->setFlag( QGraphicsItem::ItemIsSelectable, false );
        lsmd->setAcceptedMouseButtons( Qt::NoButton );
        lsmd->setResistance( m_resistance );
        lsmd->setMaxCurrent( m_maxCurrent );
        lsmd->setThreshold( m_threshold );
        lsmd->setColorStr( colorStr() );

        m_anodePin  [n*8+i] = lsmd->getEpin(0);
        m_cathodePin[n*8+i] = lsmd->getEpin(1);
        m_segment   [n*8+i] = lsmd;
    }
    m_segment[n*8+0]->setPos( x-5, -20 );
    m_segment[n*8+1]->setPos( x+11.5, -16 );
    m_segment[n*8+1]->setRotation(96);
    m_segment[n*8+2]->setPos( x+10, 3 );
    m_segment[n*8+2]->setRotation(96);
    m_segment[n*8+3]->setPos( x-8, 19 );
    m_segment[n*8+4]->setPos( x-9, 3 );
    m_segment[n*8+4]->setRotation(96);
    m_segment[n*8+5]->setPos( x-7.5, -16 );
    m_segment[n*8+5]->setRotation(96);
    m_segment[n*8+6]->setPos( x-6.5, 0 );
    m_segment[n*8+7]->setPos( x+12, 19 );
}

void SevenSegment::setHidden( bool hid, bool hidArea, bool hidLabel )
{
    Component::setHidden( hid, hidArea, hidLabel );
    if( hid ) m_area = QRect(-16,-24  , 32*m_numDisplays, 48 );
    else      m_area = QRect(-18,-24-4, 32*m_numDisplays+4, 48+8 );
}

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

    Component::paintSelected( p );
}
