#include <kapp.h>
#include <kstddirs.h>

#include <tdelocale.h>
#include <tqbitmap.h>
#include <tqstring.h>
#include <tqmsgbox.h>
#include <tqfileinfo.h>

#include "status.h"

Status::Status( TQWidget *parent, const char *name, int Scheme, int Mode ) :
    TQWidget( parent, name )
{
    actualLifes = 0;
    actualLevel = 0;

    lifesPix = NULL;
    levelPix = NULL;

    scheme = Scheme;
    mode = Mode;
    level = 0;

    confScheme();
}

TQPtrList<TQPixmap> *Status::loadPixmap(TQWidget *parent, TQString pixmapName,
                                   TQPtrList<TQPixmap> *pixmaps)
{
    if (pixmaps == NULL) {
        pixmaps = new TQPtrList<TQPixmap>;
        pixmaps->setAutoDelete(TRUE);
    }

    if (!pixmaps->isEmpty())
        pixmaps->clear();

    TQPixmap PIXMAP(pixmapName);
    if (PIXMAP.isNull() || PIXMAP.mask() == NULL) {
        TQString msg = i18n("The pixmap could not be contructed.\n\n"
                           "The file '@PIXMAPNAME@' does not exist,\n"
                           "or is of an unknown format.");
        msg.replace(TQRegExp("@PIXMAPNAME@"), pixmapName);
        TQMessageBox::information(parent, i18n("Initialization Error"), msg);
        return 0;
    }

    int height = PIXMAP.height();
    int width = (height == 0) ? 0 : PIXMAP.width()/(PIXMAP.width()/height);
    
    TQBitmap BITMAP;
    TQBitmap MASK;

    BITMAP = *PIXMAP.mask();
    MASK.resize(width, height);

    for (int x = 0; x < PIXMAP.width()/width; x++) {
        TQPixmap *pixmap = new TQPixmap(width, height);
        pixmaps->append(pixmap);
        bitBlt(pixmap, 0, 0, &PIXMAP, x*width, 0, width, height, CopyROP, TRUE);
        bitBlt(&MASK, 0, 0, &BITMAP, x*width, 0, width, height, CopyROP, TRUE);
        pixmap->setMask(MASK);
    }

    return pixmaps;
}

void Status::paintEvent( TQPaintEvent *)
{
    for (int x = 0; x < actualLifes && !lifesPix->isEmpty(); x++)
        bitBlt(this, lifesPix->at(0)->width()+(lifesPix->at(0)->width()*x), 
               (height()-lifesPix->at(0)->height())/2,
               lifesPix->at(0), 0, 0,
               lifesPix->at(0)->width(), lifesPix->at(0)->height());

    for (int x = 0; x < actualLevel && !levelPix->isEmpty(); x++) {
        erase((width()-levelPix->at(x)->width()*2)-(levelPix->at(x)->width()*levelPos[x]),
              (height()-levelPix->at(x)->height())/2,
              levelPix->at(x)->width(), levelPix->at(x)->height());
        bitBlt(this, (width()-levelPix->at(x)->width()*2)-(levelPix->at(x)->width()*levelPos[x]),
               (height()-levelPix->at(x)->height())/2,
               levelPix->at(x), 0, 0,
               levelPix->at(x)->width(), levelPix->at(x)->height());
    }
}

void Status::initPixmaps()
{
    if (lastLifesPixmapName != lifesPixmapName.at(level)) {
        lifesPix = loadPixmap(this, lifesPixmapName.at(level), lifesPix);
        lastLifesPixmapName = lifesPixmapName.at(level);
    }
    if (lastLevelPixmapName != levelPixmapName.at(level)) {
        levelPix = loadPixmap(this, levelPixmapName.at(level), levelPix);
        lastLevelPixmapName = levelPixmapName.at(level);
    }
}

TQString Status::decodeHexOctString(TQString s)
{
    TQString value;
    TQString valids;
    int pos, xpos = 0, opos = 0;
    int v, len, leadin;
    const char *ptr;
    uchar c;

    while (((xpos = s.find(TQRegExp("\\\\x[0-9a-fA-F]+"), xpos)) != -1) ||
           ((opos = s.find(TQRegExp("\\\\[0-7]+"), opos)) != -1)) {
        if (xpos != -1) {
            valids = "0123456789abcdef";
            leadin = 2;
            pos = xpos;
        } else {
            valids = "01234567";
            leadin = 1;
            pos = opos;
        }

        c = '\0';
        len = 0;
        value = s.mid(pos+leadin, 3);
        ptr = value.latin1();

        while (*ptr != '\0' && (v = valids.find(*ptr++, 0, FALSE)) != -1) {
            c = (c * valids.length()) + v;
            len++;
        }

        value.fill(c, 1);
        s.replace(pos, len+leadin, value);
    }

    return s;
}

void Status::fillArray(TQMemArray<int> &array, TQString values, int max)
{
    array.resize(max);
    int last = 0;
    bool ok;
    TQString value;

    for (uint i = 0; i < array.size(); i++) {
        if (values.find(',') < 0 &&  values.length() > 0) {
            value = values;
            values = "";
        }
        if (values.find(',') >= 0) {
            value = values.left(values.find(','));
            values.remove(0,values.find(',')+1);
        }
        array[i] = value.toInt(&ok);
        if (ok)
            last = array[i];
        else
            array[i] = last;
    }
}

void Status::fillStrList(TQStrList &list, TQString values, int max)
{
    if (!list.isEmpty())
        list.clear();

    TQString last = "";
    TQString value;

    for (uint i = 0; i < (uint) max; i++) {
        if (values.find(',') < 0 &&  values.length() > 0) {
            value = values;
            values = "";
        }
        if (values.find(',') >= 0) {
            value = values.left(values.find(','));
            values.remove(0,values.find(',')+1);
        }
        if (!value.isEmpty())
            last = decodeHexOctString(value);
        list.append(last.latin1());
    }
}

void Status::fillPixmapName(TQStrList &pixmapName)
{
    TQStrList list = pixmapName;

    if (!pixmapName.isEmpty())
        pixmapName.clear();

    TQString pixmap;

    TQFileInfo fileInfo;

    for (uint i = 0; i < list.count(); i++) {
            pixmap = list.at(i);

        if (pixmap.left(1) != "/" && pixmap.left(1) != "~")
              pixmap = TDEGlobal::dirs()->findResource("appdata", pixmapDirectory+pixmap);

      fileInfo.setFile(pixmap);
      if (!fileInfo.isReadable() || !fileInfo.isFile())
            pixmap = "";

      pixmapName.append(pixmap.utf8());
    }
}

void Status::confLevels(bool defGroup)
{
    if (defGroup || kapp->config()->hasKey("Levels"))
        maxLevel = kapp->config()->readNumEntry("Levels", 13);
}

void Status::confMisc(bool defGroup)
{
    if (defGroup || kapp->config()->hasKey("LevelPosition"))
        fillArray(levelPos, kapp->config()->readEntry("LevelPosition", "0,1,2,3,,4,,5,,6,,7"), maxLevel);

    if (defGroup || kapp->config()->hasKey("PixmapDirectory")) {
        pixmapDirectory = kapp->config()->readEntry("PixmapDirectory");

        if (pixmapDirectory.left(1) != "/" && pixmapDirectory.left(1) != "~")
            pixmapDirectory.insert(0, "pics/");
        if (pixmapDirectory.right(1) != "/")
            pixmapDirectory.append("/");
    }

    if (defGroup || kapp->config()->hasKey("LifesPixmapName"))
        fillStrList(lifesPixmapName,
                    kapp->config()->readEntry("LifesPixmapName", "lifes.xpm"), maxLevel+1);
    if (defGroup || kapp->config()->hasKey("LevelPixmapName"))
        fillStrList(levelPixmapName,
                    kapp->config()->readEntry("LevelPixmapName", "level.xpm"), maxLevel+1);

}

void Status::confScheme()
{
    TQString oldgroup = kapp->config()->group();
    TQString newgroup;

    // if not set, read mode and scheme from the configfile
    if (mode == -1 && scheme == -1) {           
        scheme = kapp->config()->readNumEntry("Scheme", -1);
        mode = kapp->config()->readNumEntry("Mode", -1);
        
        // if mode is not set in the defGroup-group, lookup the scheme group
        if (scheme != -1 || mode == -1) {
            newgroup.sprintf("Scheme %d", scheme);
            kapp->config()->setGroup(newgroup);

            mode = kapp->config()->readNumEntry("Mode", -1);
            kapp->config()->setGroup(oldgroup);
        }
    }

    confLevels();

    if (mode != -1) {
        newgroup.sprintf("Mode %d", mode);
        kapp->config()->setGroup(newgroup);     

        confLevels(FALSE);
    }

    if (scheme != -1) {
        newgroup.sprintf("Scheme %d", scheme);
        kapp->config()->setGroup(newgroup);     

        confLevels(FALSE);
    }

    kapp->config()->setGroup(oldgroup);

    confMisc();

    if (mode != -1) {
        newgroup.sprintf("Mode %d", mode);
        kapp->config()->setGroup(newgroup);     

        confMisc(FALSE);
    }

    if (scheme != -1) {
        newgroup.sprintf("Scheme %d", scheme);
        kapp->config()->setGroup(newgroup);

        confMisc(FALSE);
    }

    fillPixmapName(lifesPixmapName);
    fillPixmapName(levelPixmapName);

    initPixmaps();

    setFixedHeight(minHeight());

    kapp->config()->setGroup(oldgroup);
}

void Status::setScheme(int Scheme, int Mode)
{
    mode = Mode;
    scheme = Scheme;

    confScheme();

    repaint();
}

int Status::minHeight()
{
    if (lifesPix->isEmpty() && levelPix->isEmpty())
        return 0;
    if (levelPix->isEmpty())
        return lifesPix->at(0)->height();
    if (lifesPix->isEmpty())
        return levelPix->at(0)->height();
    return (lifesPix->at(0)->height() > levelPix->at(0)->height()) ?
            lifesPix->at(0)->height() : levelPix->at(0)->height();
}

int Status::minWidth()
{
    if (lifesPix->isEmpty() && levelPix->isEmpty())
        return 0;
    if (levelPix->isEmpty())
        return lifesPix->at(0)->width();
    if (lifesPix->isEmpty())
        return levelPix->at(0)->width();
    return (lifesPix->at(0)->width() > levelPix->at(0)->width()) ?
            lifesPix->at(0)->width() : levelPix->at(0)->width();
}

void Status::setLifes(int lifes)
{
    actualLifes = lifes;
    repaint();
}

void Status::setLevel(int Level)
{
    level = Level;

    initPixmaps();

    actualLevel = (level > (int) levelPix->count()) ? (int) levelPix->count() : level;
    repaint();
}

#include "status.moc"
