/***************************************************************************
 *   Copyright (C) 2012 by santiago González                               *
 *   santigoro@gmail.com                                                   *
 *                                                                         *
 *   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 3 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, see <http://www.gnu.org/licenses/>.  *
 *                                                                         *
 ***************************************************************************/

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


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

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

SevenSegment::SevenSegment( QObject* parent, QString type, QString id )
    : Component( parent, type, id ), eElement( id.toStdString() )
{
    setId( id );
    m_idLabel->setPos( 30, -70);

    m_color = QColor(0,0,0);
    m_commonCathode = true;
    m_numDisplays = 0;
    m_resistance = 1;
    m_area = QRect( -16, -24-1, 32, 48+2 );

    m_ePin.resize(8);

    // Create Pins
    QString nodid;
    QString pinid;

    // Create Pins & eNodes for 7 segments
    for( int i=0; i<7; i++ )
    {
        pinid = QString( 97+i ); // a..g

        nodid = m_id;
        nodid.append(QString("-pin_")).append( pinid );
        m_ePin[i] = new Pin( 180, QPoint( -16-8, -24+i*8 ), nodid, 0, this );
    }
    // Pin dot
    nodid = m_id;
    nodid.append(QString("-pin_dot"));
    m_ePin[7] = new Pin( 270, QPoint( -8, 24+8 ), nodid, 0, this );

    setNumDisplays(1);
}
SevenSegment::~SevenSegment() { }

int SevenSegment::numDisplays()
{
    return m_numDisplays;
}

void SevenSegment::setColor( LedBase::LedColor color ) 
{ 
    foreach( LedSmd* segment, m_segment )
        segment->setColor( color ); 
}

LedBase::LedColor SevenSegment::color() 
{ 
    return m_segment[0]->color(); 
}

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

    m_area = QRect( -16, -24-1, displays*32, 48+2 );

    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;
    update();
}

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

bool SevenSegment::isCommonCathode()
{
    return m_commonCathode;
}

void SevenSegment::setCommonCathode( bool isCommonCathode )
{
    bool pauseSim = Simulator::self()->isRunning();
    if( pauseSim ) Simulator::self()->pauseSim();

    m_commonCathode = isCommonCathode;

    if( pauseSim ) Simulator::self()->runContinuous();
}

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

void SevenSegment::initialize()
{
    for( int i=0; i<8; i++ ) m_enode[i] = m_ePin[i]->getEnode(); // Get the actual eNode of pin i

    for( int i=0; i<m_numDisplays; i++ )
    {
        eNode* commonEnode = m_commonPin[i]->getEnode();     // Get the actual eNode of common

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

void SevenSegment::deleteDisplay( int dispNumber )
{
    Pin* pin = static_cast<Pin*>(m_commonPin[dispNumber]);
    if( pin->isConnected() ) pin->connector()->remove();

    //pin->deleteLater();

    for( int i=0; i<8; i++ ) m_segment[dispNumber*8+i]->remove();
    Circuit::self()->update();
    update();
}

void SevenSegment::createDisplay( int dispNumber )
{
    int x = 32*dispNumber;
    QString nodid;
    QString pinid;
    //LedSmd* segment[8];

    // Pin common
    nodid = m_id;
    nodid.append(QString("-pin_common")).append( QString( 97+dispNumber ) );
    m_commonPin[dispNumber] = new Pin( 270, QPoint( x+8, 24+8 ), nodid, 0, this );

    // Create segments
    for( int i=0; i<8; i++ )
    {
        nodid = m_id;
        pinid = QString( 97+i );
        nodid.append(QString("-led_")).append( pinid );
        LedSmd* lsmd;
        if( i<7 ) lsmd = new LedSmd( this, "LEDSMD", nodid, QRectF(0, 0, 13.5, 1.5) ); // Segment
        else      lsmd = new LedSmd( this, "LEDSMD", nodid, QRectF(0, 0, 1.5, 1.5) );  // Point
        lsmd->setParentItem(this);
        lsmd->setEnabled(false);
        lsmd->setNumEpins(2);
        lsmd->setMaxCurrent( 0.02 );

        m_anodePin[dispNumber*8+i]= lsmd->getEpin(0);
        m_cathodePin[dispNumber*8+i] = lsmd->getEpin(1);

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

void SevenSegment::remove()
{
    for( int i=0; i<8; i++ )
        if( m_ePin[i]->isConnected() ) (static_cast<Pin*>(m_ePin[i]))->connector()->remove();

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

    for( int i=0; i<m_numDisplays; i++ ) deleteDisplay( i );
        
    Component::remove();
}

void SevenSegment::paint( QPainter* p, const QStyleOptionGraphicsItem* option, QWidget* widget )
{
    Q_UNUSED(option); Q_UNUSED(widget);

    Component::paint( p, option, widget );

    p->drawRect( boundingRect() );
}

#include "moc_sevensegment.cpp"

