bool FeatureConnector::loadMetaData(Ilwis::IlwisObject *obj)
{
    bool ok = CoverageConnector::loadMetaData(obj);
    if ( !ok)
        return false;
    FeatureCoverage *fcoverage = static_cast<FeatureCoverage *>(obj);
    IlwisTypes coverageType = itPOINT;

    int features = _odf->value("PointMap","Points").toInt(&ok);
    if (!ok) {
        coverageType = itLINE;
        features = _odf->value("SegmentMapStore","Segments").toInt(&ok);
        if (!ok) {
            coverageType = itPOLYGON;
            features = _odf->value("PolygonMapStore","Polygons").toInt(&ok);
        }
    }

    if (ok){
        fcoverage->featureTypes(coverageType);
        fcoverage->setFeatureCount(coverageType, features);
    }
    else
       return ERROR2(ERR_INVALID_PROPERTY_FOR_2,"Records",obj->name());

    ITable tbl = fcoverage->attributeTable();
    tbl->setRows(fcoverage->featureCount());
    return true;

}
bool FeatureConnector::loadBinaryData(Ilwis::IlwisObject *obj) {
    if ( obj == nullptr)
        return false;

    FeatureCoverage *fcoverage = static_cast<FeatureCoverage *>(obj);

    QString file = _odf->value("BaseMap", "AttributeTable");
    ITable extTable;
    if ( file != sUNDEF) {
        if(!extTable.prepare(file)){
            kernel()->issues()->log(file,TR(ERR_NO_INITIALIZED_1).arg(file),IssueObject::itWarning);
            return false;
        }
    }
    bool ok = false;
     if (fcoverage->featureTypes() == itPOINT)
        ok = loadBinaryPoints(fcoverage);
    else if (fcoverage->featureTypes() == itLINE)
        ok = loadBinarySegments(fcoverage);
    else if (fcoverage->featureTypes() == itPOLYGON)
        ok = loadBinaryPolygons(fcoverage);
    if ( ok && extTable.isValid()) {
        ITable attTbl = fcoverage->attributeTable();
        quint32 keyIndex = attTbl->columnIndex(COVERAGEKEYCOLUMN);
        for(quint32 rowExt=0; rowExt < extTable->records(); ++rowExt) {
            vector<QVariant> rec = extTable->record(rowExt);
            for(quint32 rowAtt = 0; rowAtt < attTbl->records(); ++rowAtt ) {
                if ( attTbl->cell(keyIndex, rowAtt) == rowExt + 1) {
                    attTbl->record(rowAtt,rec);
                }
            }
        }
    }
    return ok;
}
bool FeatureConnector::loadMetaData(Ilwis::IlwisObject *obj,const IOOptions& options)
{
    bool ok = CoverageConnector::loadMetaData(obj, options);
    if ( !ok)
        return false;
    FeatureCoverage *fcoverage = static_cast<FeatureCoverage *>(obj);
    fcoverage->setFeatureCount(itFEATURE, iUNDEF, FeatureInfo::ALLFEATURES);
    IlwisTypes coverageType = itPOINT;

    int features = _odf->value("PointMap","Points").toInt(&ok);
    if (!ok) {
        coverageType = itPOLYGON;
        features = _odf->value("PolygonMapStore","Polygons").toInt(&ok);
        if (!ok) {
            coverageType = itLINE;
            features = _odf->value("SegmentMapStore","Segments").toInt(&ok);
        }
    }

    if (ok){
        // overwrite with the correct value from the attribute table if available (without computing it by reading the binary data!)
        if (hasProperty("TableRecordCount"))
            features = getProperty("TableRecordCount").toInt();
        fcoverage->featureTypes(coverageType);
        fcoverage->setFeatureCount(coverageType, features,0);
    }
    else
       return ERROR2(ERR_INVALID_PROPERTY_FOR_2,"Records",obj->name());

    //ITable tbl = fcoverage->attributeTable();
    //tbl->recordCount(fcoverage->featureCount(itFEATURE,true));
    return true;

}
bool FeatureConnector::storeBinaryData(IlwisObject *obj) {

    FeatureCoverage *fcov = static_cast<FeatureCoverage *>(obj);
    IlwisTypes featureTypes = fcov->featureTypes();
    bool ok = true;

    ok &= storeBinaryData(fcov, featureTypes & itPOLYGON);
    ok &= storeBinaryData(fcov, featureTypes & itLINE);
    ok &= storeBinaryData(fcov, featureTypes & itPOINT);

    return ok;
}
bool GdalFeatureConnector::loadMetaData(Ilwis::IlwisObject *data,const IOOptions& options){

    if(!CoverageConnector::loadMetaData(data, options))
        return false;

    FeatureCoverage *fcoverage = static_cast<FeatureCoverage *>(data);
    fcoverage->setFeatureCount(itFEATURE, iUNDEF, FeatureInfo::ALLFEATURES);

    OGRLayerH hLayer = getLayerHandle();

    if ( hLayer) {
        //feature types
        IlwisTypes type = translateOGRType(gdal()->getLayerGeometry(hLayer));
        if (type == itUNKNOWN){
            WARN(QString("Unknown feature type of layer %1 from: %2").arg(0).arg(_filename.toString()));
        }else{
            fcoverage->featureTypes(type);
        }

        //feature counts
        int temp = gdal()->getFeatureCount(hLayer, FALSE);//TRUE to FORCE databases to scan whole layer, FALSe can end up in -1 for unknown result
        if (temp == -1){
            WARN(QString("Couldn't determine feature count of layer %1 from meta data of %2").arg(0).arg(_filename.toString()));
        }else{
            int featureCount = fcoverage->featureCount(type);
            featureCount += temp;
            fcoverage->setFeatureCount(type, featureCount,0); // subgeometries are not known at this level
        }
        //attribute table
        ITable attTable;
        Resource resource(_filename, itFLATTABLE);
        if(!attTable.prepare(resource,{"asflattable", true})) {//will load whole meta data of the table
            ERROR1(ERR_NO_INITIALIZED_1,resource.name());
            return false;
        }
        fcoverage->setAttributes(attTable);

        //layer envelopes/extents
        Envelope bbox;
        OGREnvelope envelope;//might sometimes be supported as 3D now only posssible from OGRGeometry
        OGRErr err = gdal()->getLayerExtent(hLayer, &envelope , FALSE);//TRUE to FORCE
        if (err != OGRERR_NONE){
            if (err == OGRERR_FAILURE){//on an empty layer or if simply too expensive(FORECE=FALSE) OGR_L_GetExtent may return OGRERR_FAILURE
                WARN(QString("Couldn't determine the extent of layer %1 from meta data of %2").arg(0).arg(_filename.toString()));
            }else{
                ERROR0(QString("Couldn't load extent of layer %1 from %2: %3").arg(0).arg(_filename.toString()).arg(gdal()->translateOGRERR(err)));
            }
        }else{
            bbox = Envelope(Coordinate(envelope.MinX,envelope.MinY),Coordinate(envelope.MaxX,envelope.MaxY));
        }
        fcoverage->envelope(bbox);
//        fcoverage->coordinateSystem()->envelope(bbox);
    }

    gdal()->closeFile(sourceRef().toLocalFile(), data->id());

    return true;
}
bool GdalFeatureConnector::loadData(IlwisObject* data, const IOOptions &){

    if(!GdalConnector::loadMetaData(data, IOOptions()))
        return false;

    bool ok = true;
    FeatureCoverage *fcoverage = static_cast<FeatureCoverage *>(data);
    if ( fcoverage->isValid() ) {
        ITable attTable = fcoverage->attributeTable();
        if (!attTable.isValid()){
            ERROR2(ERR_NO_INITIALIZED_2,"attribute table",_filename.toString());
            return false;
        }
        fcoverage->setFeatureCount(itFEATURE, iUNDEF, FeatureInfo::ALLFEATURES); // metadata already set it to correct number, creating new features will up the count agains; so reset to 0.

        OGRLayerH hLayer = getLayerHandle();
        if ( hLayer) {
            GdalTableLoader loader;
            attTable->dataLoaded(true); // new table, dont want any loading behaviour
            loader.setColumnCallbacks(attTable.ptr(), hLayer);
            std::vector<QVariant> record(attTable->columnCount());
            OGRFeatureH hFeature = 0;
            gdal()->resetReading(hLayer);
            //each FEATURE
            try {
                while( (hFeature = gdal()->getNextFeature(hLayer)) != NULL){
                    loader.loadRecord(attTable.ptr(), hFeature, record);
                    geos::geom::Geometry * geometry = fillFeature(fcoverage, gdal()->getGeometryRef(hFeature));
                    if (geometry){
                        auto feature = fcoverage->newFeature(geometry, false);
                        feature->record(record);
                    }else{
                        ERROR1("GDAL error during load of binary data: no geometry detected for feature in %1", _filename.toString());
                    }
                    gdal()->destroyFeature( hFeature );
                }
            } catch (FeatureCreationError& ) {
                gdal()->destroyFeature( hFeature );
                ok = false;
            }
        }
        //layer envelopes/extents
        Envelope bbox;
        OGREnvelope envelope;//might sometimes be supported as 3D now only posssible from OGRGeometry
        OGRErr err = gdal()->getLayerExtent(hLayer, &envelope , TRUE);//TRUE to FORCE
        if (err != OGRERR_NONE && fcoverage->featureCount() != 0){
            ERROR0(QString("Couldn't load extent of a layer from %1 after binary was loaded: %2").arg(_filename.toString()).arg(gdal()->translateOGRERR(err)));
        }else{
            bbox = Envelope(Coordinate(envelope.MinX,envelope.MinY),Coordinate(envelope.MaxX,envelope.MaxY));
        }
        fcoverage->envelope(bbox);
    }
    gdal()->closeFile(sourceRef().toLocalFile(), data->id());
    _binaryIsLoaded = ok;
    return ok;
}
bool FeatureConnector::storeBinaryDataTable(IlwisObject *obj, IlwisTypes tp, const QString& baseName)
{
    FeatureCoverage *fcoverage = static_cast<FeatureCoverage *>(obj);
    ITable attTable = fcoverage->attributeTable();
    if ( attTable.isValid() && attTable->columnCount() > 0) {
        QFileInfo basename (baseName);
        QScopedPointer<TableConnector> conn(createTableStoreConnector(attTable, fcoverage, tp, basename.baseName()));
        IFeatureCoverage cov(fcoverage);
        FeatureIterator iter(cov);
        quint32 i = 0;
        std::vector<quint32> recordnr(fcoverage->featureCount(tp));
        for(quint32 rec=0; rec < fcoverage->featureCount(); ++rec){
            if ( hasType((*iter)->geometryType(), tp))
                recordnr[i++] = rec;
            ++iter;
        };
        conn->selectedRecords(recordnr);
        return conn->storeBinaryData(attTable.ptr());

    }

    return true; // no store needed
}
bool FeatureConnector::loadData(Ilwis::IlwisObject *obj, const IOOptions &) {
    if ( obj == nullptr)
        return false;

    FeatureCoverage *fcoverage = static_cast<FeatureCoverage *>(obj);

    QString file = _odf->value("BaseMap", "AttributeTable");
    ITable extTable;
    if ( file != sUNDEF) {
        if(!extTable.prepare(file)){
            kernel()->issues()->log(file,TR(ERR_NO_INITIALIZED_1).arg(file),IssueObject::itWarning);
            return false;
        }
    }
    bool ok = false;

    try {
        _binaryIsLoaded = true; // to prevent any subsequent calls to this routine while loading (which mat trigger it).
         if (fcoverage->featureTypes() == itPOINT)
             ok = loadBinaryPoints(fcoverage);
         else if (fcoverage->featureTypes() == itLINE)
             ok = loadBinarySegments(fcoverage);
         else if (fcoverage->featureTypes() == itPOLYGON)
             ok = loadBinaryPolygons(fcoverage);

         _binaryIsLoaded = ok;

         if ( ok && extTable.isValid()) {
             ITable attTbl = fcoverage->attributeTable();
             quint32 nrAttrCols = std::min(attTbl->columnCount(),extTable->columnCount());
            // quint32 keyIndex = extTable->columnIndex(COVERAGEKEYCOLUMN);
             for(quint32 rowExt=0; rowExt < extTable->recordCount(); ++rowExt) {
                 if ( rowExt < fcoverage->featureCount()){
                     vector<QVariant> rec = extTable->record(rowExt);
                     rec.resize(nrAttrCols); // extTable received an extra "Domain" column, which is not there (and will not be there) in attTbl
                     attTbl->record(rowExt,rec);
                 }
             }
         }
    } catch (FeatureCreationError& ) {
    }
    if ( ok)
        _binaryIsLoaded = true;
    return ok;
}