#include "BinWordEditor.h"
#include "BinValueEditor.h"
#include "MemoryDisplayer.h"
#include <qregexp.h>
#include <qtooltip.h>
#include <qapplication.h>

#include <iostream>
#include <cstdio>

using namespace std ;

BinWordEditor::BinWordEditor(FragBuffer& me, unsigned int index ,
                             const QString& desc,
                             bool /* byteAddr */ , QWidget *parent) :
        QVBox(parent), word(me+index)
{
    const char *p = desc.latin1() ;
    QString bitname , bitname1 , doc ;
    int b1,b2 ;
    BinValueEditor *bve ;

    QString a;

    setMargin(0) ;
    setSpacing(3) ;
    val = new QLineEdit(a.sprintf("%04X", *word & 0xFFFF ), this) ;
    val->setReadOnly(true) ;

    (new QVBox(this)) ; // add 3 pix space


    int w = fontMetrics().size(SingleLine,"AAAA").width() + 6;
    val->setMaximumWidth(w) ;
    

    while(parse(p,bitname,doc, b1,b2))
    {
        // the normal usage is to specify b1 >= b2
        // but this code can cope with b1 < b2
        if(b1 < b2)
        {
            int k = b1 ; b1 = b2 ; b2 = k ;
        }
     
        for(int b = b1 ; b >= b2 ; --b )
        {
            bitname1.sprintf(bitname,b-b2) ;
            bve = new BinValueEditor( word, b, bitname1, this,
                                      bitname != "0" && bitname != "1" && bitname != "X") ;
            // special case : non implemented bits  cannot be edited
            if( doc != "")
            {
                QToolTip::add(bve, doc) ;
            }
            connect(bve, SIGNAL(bitChanged()),  this, SLOT(updateHexDisplay())) ;
            connect(this, SIGNAL(wordChanged()),  bve, SLOT(updateDisplay())) ;
        }
    }
}

bool BinWordEditor::parse(const char*& p, QString& name, QString& doc, int& b1, int& b2)
{
    char bitname[40] ;
    int a,b , n, i ;

    name="" ;
    while(*p ==  ' ') ++p ;
    // XX[a-b] means XX0 ... XXa-b+1
    i=sscanf(p,"%[_$|A-Za-z0-9/-][%d-%d]%n", bitname,&a,&b, &n) ;
    if( i == 3 )
    {
        name = bitname ; b1 = a ;  b2 = b ; p += n ;
        name += "-%d" ;
        parseDoc(p,doc) ;
        return true ;
    }
    // XX(a-b) means that all the bits from b to a are identical
    // and are (identically) named XX
    i=sscanf(p,"%[_$|A-Za-z0-9/-](%d-%d)%n", bitname,&a,&b, &n) ;
    if( i == 3 )
    {
        name = bitname ; b1 = a ;  b2 = b ; p += n ;
        parseDoc(p,doc) ;
        return true ;
    }
    i=sscanf(p,"%[_$|A-Za-z0-9/-][%d]%n", bitname,&a, &n) ;
    if( i == 2 )
    {
        name = bitname ; b1 = a ;  b2 = a ; p += n ;
        parseDoc(p,doc) ;
        return true ;
    }
    // XX[a] and XX(a) have the same meaning
    i=sscanf(p,"%[_$|A-Za-z0-9/-](%d)%n", bitname,&a, &n) ;
    if( i == 2 )
    {
        name = bitname ; b1 = a ;  b2 = a ; p += n ;
        parseDoc(p,doc) ;
        return true ;
    }

    return false ;
}

void BinWordEditor::updateHexDisplay()
{
    QString s ;
    val->setText(s.sprintf("%04X", *word & 0xFFFF)) ;
}

void BinWordEditor::updateDisplay()
{
    updateHexDisplay() ;
    emit wordChanged() ;
}

unsigned int BinWordEditor::getValue()
{
    return  *word ;
}


/** No descriptions */
void BinWordEditor::parseDoc(const char*& p, QString& doc)
{
    doc = "" ;
    while(*p == ' ' ) ++p ;
    if(*p == '{')
    {
        for(++p; *p && *p != '}' ; ++p ) doc += *p ;
        if(*p) ++p ;
    }

}
