#include "qgspointconverterplugin.h"
#include "qgisinterface.h"
#include "qgsgeometry.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"

#include <QFileDialog>
#include <QMessageBox>
#include <QTextStream>
#include <QtGui/QAction>
#define QGISEXTERN extern "C" __declspec( dllexport )

QgsPointConverterPlugin::QgsPointConverterPlugin(QgisInterface* iface): mIface(iface), mAction(0)
{
}
QgsPointConverterPlugin::~QgsPointConverterPlugin()
{
}
void QgsPointConverterPlugin::initGui()
{
    mAction = new QAction(tr("&Convert to point"),this);
    connect(mAction,SIGNAL(activated()),this,SLOT(convertToPoint()));
    mIface->addToolBarIcon(mAction);
    mIface->addPluginToMenu(tr("&Convert to point"), mAction);
}
void QgsPointConverterPlugin::unload()
{
    mIface->removeToolBarIcon(mAction);
    mIface->removePluginMenu(tr("&Convert to point"), mAction);
    delete mAction;
}
void QgsPointConverterPlugin::convertToPoint()
{
    qWarning("in method convertToPoint");
    QgsMapLayer* theMapLayer = mIface->activeLayer();
    if(!theMapLayer)
    {
        QMessageBox::information(0, tr("no active layer"),tr("this plugin needs an active point vector layer to make conversions to points"), QMessageBox::Ok);
        return;
    }
    QgsVectorLayer* theVectorLayer = dynamic_cast<QgsVectorLayer*>(theMapLayer);
    if(!theVectorLayer)
    {
        QMessageBox::information(0, tr("no vector layer"),tr("this plugin needs an active point vector layer to make conversions to points"), QMessageBox::Ok);
        return;
    }
    QString fileName = QFileDialog::getSaveFileName();
    if(!fileName.isNull())
    {
        qWarning("The selected filename is: " + fileName);
        QFile f(fileName);
        if(!f.open(QIODevice::WriteOnly))
        {
            QMessageBox::information(0, "error", "Could not open file", QMessageBox::Ok);
            return;
        }
        QTextStream theTextStream(&f);
        theTextStream.setRealNumberNotation(QTextStream::FixedNotation);
        QgsFeature currentFeature;
        QgsGeometry* currentGeometry = 0;
        QgsVectorDataProvider* provider = theVectorLayer->dataProvider();
        if(!provider)
        {
            return;
        }

        theVectorLayer->select(provider->attributeIndexes(),theVectorLayer->extent(), true, false);
        //write header
        theTextStream << "x,y";
        QMap<QString, int> fieldMap = provider->fieldNameMap();
        //We need the attributes sorted by index.
        //Therefore we insert them in a second map where key / values are exchanged
        QMap<int, QString> sortedFieldMap;
        QMap<QString, int>::const_iterator fieldIt = fieldMap.constBegin();
        for(; fieldIt != fieldMap.constEnd(); ++fieldIt)
        {
            sortedFieldMap.insert(fieldIt.value(), fieldIt.key());
        }
        QMap<int, QString>::const_iterator sortedFieldIt = sortedFieldMap.constBegin();
        for(; sortedFieldIt != sortedFieldMap.constEnd(); ++sortedFieldIt)
        {
            theTextStream << "," << sortedFieldIt.value();
        }
        theTextStream << endl;
        while(theVectorLayer->nextFeature(currentFeature))
        {
            QString featureAttributesString;
            const QgsAttributeMap& map = currentFeature.attributeMap();
            QgsAttributeMap::const_iterator attributeIt = map.constBegin();
            for(; attributeIt != map.constEnd(); ++attributeIt)
            {
                featureAttributesString.append(",");
                featureAttributesString.append(attributeIt.value().toString());
            }
            currentGeometry = currentFeature.geometry();
            if(!currentGeometry)
            {
                continue;
            }
            switch(currentGeometry->wkbType())
            {
                case QGis::WKBPoint:
                case QGis::WKBPoint25D:
                    convertPoint(currentGeometry, featureAttributesString,theTextStream);
                    break;
                case QGis::WKBMultiPoint:
                case QGis::WKBMultiPoint25D:
                    convertMultiPoint(currentGeometry, featureAttributesString,theTextStream);
                    break;
                case QGis::WKBLineString:
                case QGis::WKBLineString25D:
                    convertLineString(currentGeometry, featureAttributesString,theTextStream);
                    break;
                case QGis::WKBMultiLineString:
                case QGis::WKBMultiLineString25D:
                    convertMultiLineString(currentGeometry, featureAttributesString,theTextStream);
                    break;
                case QGis::WKBPolygon:
                case QGis::WKBPolygon25D:
                    convertPolygon(currentGeometry, featureAttributesString,theTextStream);
                    break;
                case QGis::WKBMultiPolygon:
                case QGis::WKBMultiPolygon25D:
                    convertMultiPolygon(currentGeometry, featureAttributesString,theTextStream);
                    break;
            }
        }
    }
}
//geometry converter functions
void QgsPointConverterPlugin::convertPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
{
    QgsPoint p = geom->asPoint();
    stream << p.x() << "," << p.y();
    stream << attributeString;
    stream << endl;
}
void QgsPointConverterPlugin::convertMultiPoint(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
{
    QgsMultiPoint mp = geom->asMultiPoint();
    QgsMultiPoint::const_iterator it = mp.constBegin();
    for(; it != mp.constEnd(); ++it)
    {
        stream << (*it).x() << "," << (*it).y();
        stream << attributeString;
        stream << endl;
    }
}
void QgsPointConverterPlugin::convertLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
{
    QgsPolyline line = geom->asPolyline();
    QgsPolyline::const_iterator it = line.constBegin();
    for(; it != line.constEnd(); ++it)
    {
        stream << (*it).x() << "," << (*it).y();
        stream << attributeString;
        stream << endl;
    }
}
void QgsPointConverterPlugin::convertMultiLineString(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
{
    QgsMultiPolyline ml = geom->asMultiPolyline();
    QgsMultiPolyline::const_iterator lineIt = ml.constBegin();
    for(; lineIt != ml.constEnd(); ++lineIt)
    {
        QgsPolyline currentPolyline = *lineIt;
        QgsPolyline::const_iterator vertexIt = currentPolyline.constBegin();
        for(; vertexIt != currentPolyline.constEnd(); ++vertexIt)
        {
            stream << (*vertexIt).x() << "," << (*vertexIt).y();
            stream << attributeString;
            stream << endl;
        }
    }
}
void QgsPointConverterPlugin::convertPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
{
    QgsPolygon polygon = geom->asPolygon();
    QgsPolygon::const_iterator it = polygon.constBegin();
    for(; it != polygon.constEnd(); ++it)
    {
        QgsPolyline currentRing = *it;
        QgsPolyline::const_iterator vertexIt = currentRing.constBegin();
        for(; vertexIt != currentRing.constEnd(); ++vertexIt)
        {
            stream << (*vertexIt).x() << "," << (*vertexIt).y();
            stream << attributeString;
            stream << endl;
        }
    }
}
void QgsPointConverterPlugin::convertMultiPolygon(QgsGeometry* geom, const QString& attributeString, QTextStream& stream) const
{
    QgsMultiPolygon mp = geom->asMultiPolygon();
    QgsMultiPolygon::const_iterator polyIt = mp.constBegin();
    for(; polyIt != mp.constEnd(); ++polyIt)
    {
        QgsPolygon currentPolygon = *polyIt;
        QgsPolygon::const_iterator ringIt = currentPolygon.constBegin();
        for(; ringIt != currentPolygon.constEnd(); ++ringIt)
        {
            QgsPolyline currentPolyline = *ringIt;
            QgsPolyline::const_iterator vertexIt = currentPolyline.constBegin();
            for(; vertexIt != currentPolyline.constEnd(); ++vertexIt)
            {
                stream << (*vertexIt).x() << "," << (*vertexIt).y();
                stream << attributeString;
                stream << endl;
            }
        }
    }
}

QGISEXTERN QgisPlugin* classFactory(QgisInterface* iface)
{
    return new QgsPointConverterPlugin(iface);
}
QGISEXTERN QString name()
{
    return "point converter plugin";
}
QGISEXTERN QString description()
{
    return "A plugin that converts vector layers to delimited text point files";
}
QGISEXTERN QString version()
{
    return "0.00001";
}
// Return the type (either UI or MapLayer plugin)
QGISEXTERN int type()
{
    return QgisPlugin::UI;
}
// Delete ourself
QGISEXTERN void unload(QgisPlugin* theQgsPointConverterPluginPointer)
{
    delete theQgsPointConverterPluginPointer;
}
