/*
    Copyright 2011 Julian Helfferich <julian.helfferich@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 2 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 "levelloader.h"
#include "globals.h"

#include <QDomDocument>
#include <QFile>

// These can be removed when KConfig style levelsets are no longer supported
#include <KConfig>
#include <KConfigGroup>

#include <KDebug>
#include <KStandardDirs>

LevelLoader::LevelLoader(QObject *parent)
  : QObject(parent)
{
    m_levelname = QString();
    m_level = 0;
    m_levelset = 0;
}

LevelLoader::~LevelLoader()
{
    delete m_levelset;
}

int LevelLoader::level() const
{
    return m_level;
}

void LevelLoader::setLevel(int level)
{
    m_level = level;
}

QString LevelLoader::levelset() const
{
    return m_levelname;
}

void LevelLoader::setLevelset(const QString& levelname)
{
    if( levelname == m_levelname ){
        return;
    }
    m_levelname = levelname;

    // Loading document model
    // Locating the path in the filesystem
    QString path = "levelsets/" + m_levelname + ".levelset";
    path =  KStandardDirs::locate("appdata", path);
    // --
    
    delete m_levelset;
    
    m_levelset = new QDomDocument( m_levelname );
    QFile file( path );
    if( !file.open( QIODevice::ReadOnly ) ){
        kError() << "Can't open file " << path << endl;
    }
  
    QString errorString;
    int errorLine;
    int errorColumn;
    if( !m_levelset->setContent( &file, false, &errorString, &errorLine, &errorColumn ) ){
        file.close();
        // Testing whether levelset is of old KConfig style
        KConfig kconfigfile(path, KConfig::SimpleConfig);
        if( kconfigfile.hasGroup( "level1" ) ){
            // Levelset is in KConfig style
            m_oldstyle = true;
            kError() << "Warning: Using deprecated KConfig-levelset. Please change to XML-Style.\n";
        } else {
            kError() << "Can't read levelset from " << path << "\nError: " << errorString <<
                        " in Line " << errorLine << ", Column " << errorColumn << endl;
        }
    } else {
        // Successfully loaded QDom-style levelset
        m_oldstyle = false;
    }
    file.close();
    // --
}

void LevelLoader::loadLevel()
{   
    // Check if levelset is of KConfig-type
    if( m_oldstyle ){
        loadOldStyleLevel();
        return;
    }
    // Selecting the correct level
    m_level++;
    
    if( m_levelset == 0 ){
        kError() << "Error: No levelset specified" << endl;
        return;
    }
    
    QDomElement levels = m_levelset->documentElement();
    QDomNode node = levels.firstChild();
    for( int i = 1; i < m_level; i++ ){
        node = node.nextSibling();
    }
    // --
    
    // Load level information
    if( node.isNull() || node.toElement().tagName() != "Level" ){
        // Level not found or no more levels
        return;
    }
    
    QDomAttr attribute;
    QDomElement level = node.toElement();
    if( level.isNull() ){
        kError() << "Invalid Levelset " << m_levelname << ": Can't read level information";
    }
    attribute = level.attributeNode("Name");
    QString levelName;
    if( !attribute.isNull() ){
        levelName = level.attributeNode("Name").value();
    }
    node = node.firstChild();
    // --
    
    // Load bricks and gifts
    m_lineNumber = 0;
    while( !node.isNull() ){
        QDomElement info = node.toElement();
        if( info.isNull() ){ kError() << "Invalid levelset " << m_levelname << ": Can't read level information."; }
            
        if( info.tagName() == "Line" ){
            // Load one line of bricks
            loadLine( info );
        } else if( info.tagName() == "Gift" ){
            // Load one gift type
            loadGift( info );
        } else {
            kError() << "Invalid tag name " << info.tagName() << " has occured in level "
                     << levelName << " in levelset " << m_levelname << endl;
        }
        
        node = node.nextSibling();
    }
}

void LevelLoader::loadLine(QDomElement lineNode)
{
    // Reading the line number
    QDomAttr attribute = lineNode.attributeNode("Number");
    QDomElement attributeNode = lineNode.firstChildElement("Number");
    if( !attribute.isNull() ){
        m_lineNumber = attribute.value().toInt();
    } else if( !attributeNode.isNull() ) {
        m_lineNumber = attributeNode.text().toInt();
    } else {
        // Standard line numbering: load next line
        m_lineNumber++;
    }
    
    // Reading the brick information
    attribute = lineNode.attributeNode("Bricks");
    attributeNode = lineNode.firstChildElement("Bricks");
    QString line;
    if( !attribute.isNull() ){
        line = attribute.value();
    } else if( !attributeNode.isNull() ) {
        line = attributeNode.text();
    } else {
        line = lineNode.text();
    }

    if( line.size() > WIDTH ){
        kError() << "Invalid levelset " << m_levelname << ": too many bricks in line "
                 << m_lineNumber << endl;
    }

    emit newLine(line, m_lineNumber);
}

void LevelLoader::loadGift(QDomElement giftNode)
{
    bool nodeTextRead = false;
    // Reading the brick type
    QDomAttr attribute = giftNode.attributeNode("Type");
    QDomElement attributeNode = giftNode.firstChildElement("Type");
    QString giftType;
    if( !attribute.isNull() ){
        giftType = attribute.value();
    } else if( !attributeNode.isNull() ){
        giftType = attributeNode.text();
        nodeTextRead = true;
    } else {
        giftType = giftNode.text();
        nodeTextRead = true;
    }

    // Reading number of gifts to be distributed. If not specified one gift is placed.
    attribute = giftNode.attributeNode("Count");
    attributeNode = giftNode.firstChildElement("Count");
    int times = 1;
    bool ok = true;
    if( !attribute.isNull() ){
        times = attribute.value().toInt( &ok );
    } else if( !attributeNode.isNull() ){
        times = attributeNode.text().toInt( &ok );
        nodeTextRead = true;
    } else if( !nodeTextRead ){
        times = giftNode.text().toInt( &ok );
        if( !ok ){ times = 1; }
    }
    
    // If only one brick to be placed: see if position is given
    QString position;
    if( times == 1 ){
        attribute = giftNode.attributeNode("Position");
        attributeNode = giftNode.firstChildElement("Position");
        if( !attribute.isNull() ){
            position = attribute.value();
        } else if( !attributeNode.isNull() ){
            position = attributeNode.text();
            nodeTextRead = true;
        } else if( !nodeTextRead && giftNode.text().contains(',') ){
            position = giftNode.text();
            nodeTextRead = true;
        }
    }

    emit newGift(giftType, times, position);
}

void LevelLoader::loadOldStyleLevel()
{
    // Selecting the correct level
    m_level++;
    
    // Loading the levelset
    QString path = "levelsets/" + m_levelname + ".levelset";
    path = KStandardDirs::locate("appdata", path);
    KConfig file(path, KConfig::SimpleConfig);
    
    QString levelName("level" + QString::number(m_level));
    
    if (!file.hasGroup(levelName)) {
        // No more levels or no levels found
        return;
    }
    
    // Loading level information
    KConfigGroup lvl = file.group(levelName);
    
    // add bricks
    
    int y = 1;
    QString key("line" + QString::number(y));
    
    while(lvl.hasKey(key)) {
        // one line of bricks to be converted
        QString line = lvl.readEntry(key, "error");
        if (line == "error") {
            kError() << "Something strange happened!!\n";
            return;
        }
        
        kDebug() << line << endl;
        
        if (line.size() > WIDTH) {
            kError() << "Invalid file: too many bricks\n";
        }

        emit newLine(line, y);
        
        ++y;
        key = "line" + QString::number(y);
    }
    
    // add gifts
    
    for (int i = 0; i < GIFT_TYPES_COUNT; ++i) {
        key = GIFT_TYPES[i];
        if (!lvl.hasKey(key)) continue;
        
        QString line = lvl.readEntry(key, "error");
        if (line == "error") {
            kError() << "Impossible reading " << m_level << ":" << key << endl;
            return;
        }
        bool ok;
        int times = line.toInt(&ok);
        if (!ok) {
            kError() << m_levelname << ":" << key << " invalid number!!" << endl;
            continue;
        }

        emit newGift(key, times, QString());
    }
}
