TableConnector *CoverageConnector::createTableConnector(ITable& attTable, Coverage *coverage, IlwisTypes tp) {
    QString dataFile = coverage->name();
    QString attDom = dataFile;
    if ( hasType(tp,itRASTER)) {
        RasterCoverage *raster = static_cast<RasterCoverage *>(coverage);
        Resource resource = raster->datadef().domain()->source();
        QFileInfo inf(resource.toLocalFile());
        attDom = inf.fileName();
    }
    int index = dataFile.lastIndexOf(".");
    if ( index != -1) {
        dataFile = dataFile.left(index);
    }else{
        if ( tp == itPOLYGON)
            attDom += ".mpa";
        if ( tp == itRASTER)
            attDom += ".mpr";
        if ( tp == itPOINT)
            attDom += ".mpp";
        if ( tp == itLINE)
            attDom += ".mps";
    }
    _odf->setKeyValue("BaseMap","AttributeTable",dataFile + ".tbt");
    attTable->setName(dataFile);
    QString dir = context()->workingCatalog()->location().toLocalFile();
    QString filename = dir + "/" + dataFile + ".tbt";
    TableConnector *conn = new TableConnector(Resource(QUrl::fromLocalFile(filename), itTABLE), false);
    //attribute domains are comming from ilwis4 always uniqueid and based on the map
    conn->attributeDomain(attDom);

    return conn;
}
Grid *RasterCoverageConnector::loadGridData(IlwisObject* data) {
    auto layerHandle = gdal()->getRasterBand(_dataSet, 1);
    if (!layerHandle) {
        ERROR2(ERR_COULD_NOT_LOAD_2, "GDAL","layer");
        return 0;
    }
    RasterCoverage *raster = static_cast<RasterCoverage *>(data);
    Grid *grid = 0;
    if ( grid == 0) {

        Size sz = raster->size();
        grid =new Grid(sz);
    }
    grid->prepare();
    quint32 linesPerBlock = grid->maxLines();
    qint64 blockSizeBytes = grid->blockSize(0) * _typeSize;
    char *block = new char[blockSizeBytes];
    int count = 0; // block count over all the layers
    quint64 totalLines =grid->size().ysize();
    quint32 layer = 1;
    while(layer <= raster->size().zsize()) {
        quint64 linesLeft = totalLines;
        int gdalindex = 0; // count within one gdal layer
        while(true) {
            if ( block == 0) {
                kernel()->issues()->log(TR("Corrupt or invalid data size when reading data(GDAL connector)"));
                return 0;
            }
            if ( linesLeft > linesPerBlock)
                gdal()->rasterIO(layerHandle,GF_Read,0,gdalindex * linesPerBlock,grid->size().xsize(), linesPerBlock,
                                 block,grid->size().xsize(), linesPerBlock,_gdalValueType,0,0 );
            else {
                gdal()->rasterIO(layerHandle,GF_Read,0,gdalindex * linesPerBlock,grid->size().xsize(), linesLeft,
                                 block,grid->size().xsize(), linesLeft,_gdalValueType,0,0 );

            }
            quint32 noItems = grid->blockSize(count);
            if ( noItems == iUNDEF)
                return 0;
            std::vector<double> values(noItems);
            for(quint32 i=0; i < noItems; ++i) {
                double v = value(block, i);
                values[i] = v;
            }
            grid->setBlock(count, values, true);
            ++count;
            ++gdalindex;
            if ( linesLeft < linesPerBlock )
                break;
            linesLeft -= linesPerBlock;
        }
        if ( ++layer < raster->size().zsize())
            layerHandle = gdal()->getRasterBand(_dataSet, layer);
    }

    delete [] block;
    return grid;
}
bool RasterCoverageConnector::loadData(IlwisObject* data, const IOOptions& options ){
    quint32 bandindex = sourceRef().hasProperty("bandindex") ? sourceRef()["bandindex"].toUInt(): iUNDEF;
    auto layerHandle = gdal()->getRasterBand(_handle->handle(), bandindex != iUNDEF ? bandindex + 1 : 1);
    if (!layerHandle) {
        ERROR2(ERR_COULD_NOT_LOAD_2, "GDAL","layer");
        return false;
    }
    RasterCoverage *raster = static_cast<RasterCoverage *>(data);

    UPGrid& grid = raster->gridRef();

    quint32 linesPerBlock = grid->maxLines();
    qint64 blockSizeBytes = grid->blockSize(0) * _typeSize;
    char *block = new char[blockSizeBytes];
    quint64 totalLines =grid->size().ysize();
    std::map<quint32, std::vector<quint32> > blocklimits;

    //blocklimits; key = band number, value= blocks needed from this band
    if ( bandindex == iUNDEF)
        blocklimits = grid->calcBlockLimits(options);
    else{
        for(int i = 0; i < std::ceil((double)totalLines / linesPerBlock); ++i)
            blocklimits[bandindex].push_back(i);
    }

    for(const auto& layer : blocklimits){
        quint64 linesLeft = totalLines - grid->maxLines() * layer.second[0]; //std::min((quint64)grid->maxLines(), totalLines - grid->maxLines() * layer.second[0]);
        if ( _colorModel == ColorRangeBase::cmNONE || raster->datadef().domain()->valueType() == itPALETTECOLOR){ // palette entries are just integers so we can use the numeric read for it
            layerHandle = gdal()->getRasterBand(_handle->handle(), layer.first + 1);
            int inLayerBlockIndex = layer.second[0] % grid->blocksPerBand(); //
            for(const auto& index : layer.second) {
                quint32 offsetIndex = bandindex == iUNDEF ? layer.first : (layer.first - bandindex);
                loadNumericBlock(layerHandle, index, inLayerBlockIndex, linesPerBlock, linesLeft, block, raster,offsetIndex );

                if(!moveIndexes(linesPerBlock, linesLeft, inLayerBlockIndex))
                    break;
            }
        }else { // continous colorcase, combining 3/4 (gdal)layers into one
            int inLayerBlockIndex = layer.second[0] % grid->blocksPerBand(); //
            for(const auto& index : layer.second) {
                loadColorBlock(layer.first,index,inLayerBlockIndex,linesPerBlock,linesLeft,block,grid);

                if(!moveIndexes(linesPerBlock, linesLeft, inLayerBlockIndex)) // ensures that the administration with respect how much needs to be done is inorder
                    break;
            }
        }
    }

    delete [] block;
    _binaryIsLoaded = true;
    return true;
}
bool DownloadManager::loadData(IlwisObject *object, const IOOptions &options){
    QUrl url = _resource.url(true);

    QUrlQuery query(url);
    if ( object->ilwisType() == itRASTER){
        RasterCoverage *raster = static_cast<RasterCoverage*>(object);
        _blockSizeBytes = raster->grid()->blockSize(0);
        if ( options.contains("blockindex")){
            _currentBlock = options["blockindex"].toInt();
            int layer = _currentBlock / raster->grid()->blocksPerBand();
            int relativeBlock = _currentBlock - layer * raster->grid()->blocksPerBand();
            unsigned int minLine = raster->grid()->maxLines() * relativeBlock ;
            unsigned int maxLine = std::min( minLine + raster->grid()->maxLines(), raster->size().ysize());
            query.addQueryItem("lines",QString("%1 %2 %3").arg(layer).arg(minLine).arg(maxLine));
        }
    }
    query.addQueryItem("datatype","data");
    url.setQuery(query);
    QString urltxt = url.toString();
    _object = object;
    QNetworkRequest request(url);

    QNetworkReply *reply = kernel()->network().get(request);

    if ( object->ilwisType() == itRASTER)
        connect(reply, &QNetworkReply::readyRead, this, &DownloadManager::readReadyRaster);
    else
        connect(reply, &QNetworkReply::readyRead, this, &DownloadManager::readReady);
    connect(reply, &QNetworkReply::downloadProgress, this, &DownloadManager::downloadProgress);
    connect(reply, static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error), this, &DownloadManager::error);
    connect(reply, &QNetworkReply::finished, this, &DownloadManager::finishedData);

    QEventLoop loop; // waits for request to complete
    connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
    loop.exec();

    delete reply;

    return true;
}
bool RasterCoverageConnector::store(IlwisObject *obj, int )
{
    if(!GdalConnector::store(obj, 0))
        return false;

    RasterCoverage *raster = static_cast<RasterCoverage *>(obj);

    IDomain dom;
    if(!dom.prepare("code=value")) { //TODO  for the moment only value maps in gdal
        return ERROR1(ERR_NO_INITIALIZED_1,obj->name());
    }
    raster->datadef().domain(dom);
    Size sz = raster->size();
    GDALDataType gdalType = ilwisType2GdalType(raster->datadef().range()->determineType());
    GDALDriverH hdriver = gdal()->getGDALDriverByName(_gdalShortName.toLocal8Bit());
    if ( hdriver == 0) {
        return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2, "driver",_gdalShortName);
    }
    QString filename = constructOutputName(hdriver);

    GDALDatasetH dataset = gdal()->create( hdriver, filename.toLocal8Bit(), sz.xsize(), sz.ysize(), sz.zsize(), gdalType, 0 );
    if ( dataset == 0) {
        return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2, "data set",_filename);
    }
    bool ok = setGeotransform(raster, dataset);
    if (ok)
        ok = setSRS(raster, dataset);

    if (!ok)
        return false;

    switch(gdalType) {
    case GDT_Byte:
        ok = save<quint8>(raster, dataset,gdalType);
        break;
    case GDT_UInt16:
        ok = save<quint16>(raster, dataset,gdalType);
        break;
    case GDT_Int16:
        ok = save<qint16>(raster, dataset,gdalType);
        break;
    case GDT_Int32:
        ok = save<qint32>(raster, dataset,gdalType);
        break;
    case GDT_UInt32:
        ok = save<quint32>(raster, dataset,gdalType);
        break;
    case GDT_Float32:
        ok = save<float>(raster, dataset,gdalType);
        break;
    case GDT_Float64:
        ok = save<double>(raster, dataset,gdalType);
        break;
    default:
        ok= ERROR1(ERR_NO_INITIALIZED_1, "gdal Data type");
    }

    gdal()->close(dataset);

    return ok;
}
IlwisObject *InternalIlwisObjectFactory::createRasterCoverage(const Resource& resource, const IOOptions &options) const {
    if ( !resource.isValid()) {
        ERROR1(ERR_NO_INITIALIZED_1,"resource");
        return 0;
    }
    RasterCoverage *gcoverage = createFromResource<RasterCoverage>(resource, options);
    if (!createCoverage(resource, gcoverage, options))
        return 0;

    Size<> sz;
    QString typenm = resource["size"].typeName();
    if ( typenm == "Ilwis::Size<quint32>"){
        sz = resource["size"].value<Size<>>();
    } else if (typenm == "QSize") {
        sz = resource["size"].toSize();
    } else if (typenm == "QString") {
        QStringList parts = resource["size"].toString().split(" ");
        if ( parts.size() >= 2)
            sz = Size<>(parts[0].toInt(), parts[1].toInt(), 1);
        if ( parts.size() == 3)
            sz.zsize(parts[2].toInt());
    }

    gcoverage->gridRef()->prepare(gcoverage, sz);

    IGeoReference grf;
    QString tpnam = resource["georeference"].typeName();
    if (tpnam == "Ilwis::IGeoReference")
        grf = resource["georeference"].value<Ilwis::IGeoReference>();
    else if( tpnam == "QString"  && resource["georeference"].toString() != sUNDEF) {
        Resource newresource = resource.property2Resource("georeference", itGEOREF);
        if ( newresource.isValid()) {
            if (!grf.prepare(newresource))
                return 0;
        }
    } else if ( tpnam == "qulonglong"){
        if(!grf.prepare(resource["georeference"].value<quint64>()))
                return 0;

    } else{
        Envelope bounds = gcoverage->envelope();
        if ( bounds.isValid() && !bounds.isNull()){
            grf = new GeoReference();
            grf->create("corners");
            grf->name("subset_" + gcoverage->name());
            grf->coordinateSystem(gcoverage->coordinateSystem());
			QSharedPointer< CornersGeoReference> spGrf = grf->as< CornersGeoReference>();
			spGrf->internalEnvelope(bounds);
            grf->size(sz);
            if (!grf->compute()){
                ERROR1(ERR_COULDNT_CREATE_OBJECT_FOR_1, "Georeference");
                return 0;
            }

        }

    }
    if ( grf.isValid())
        gcoverage->georeference(grf);
    if ( sz.isValid())
        gcoverage->size(sz);

    return gcoverage;
}
bool InternalIlwisObjectFactory::createCoverage(const Resource& resource, Coverage *coverage, const IOOptions &options) const {

    if (!coverage->prepare())
        return false;

    //coverage->setName(QString("%1%2").arg(ANONYMOUS_PREFIX).arg(coverage->id()));

    ICoordinateSystem csy;
    QString typnm = resource["coordinatesystem"].typeName();
    if (typnm == "Ilwis::ICoordinateSystem")
        csy = resource["coordinatesystem"].value<Ilwis::ICoordinateSystem>();
    else if( typnm == "QString" &&
             resource["coordinatesystem"].toString() != sUNDEF  ) {
        Resource newresource = resource.property2Resource("coordinatesystem", itCOORDSYSTEM);
        if ( newresource.isValid()) {
            if (!csy.prepare(newresource,options))
                return false;
        }
    } else if ( typnm == "qulonglong"){
        if(!csy.prepare(resource["coordinatesystem"].value<quint64>()))
            return 0;
    }
    if ( csy.isValid()){
        coverage->coordinateSystem(csy);
    }

    Envelope bounds;
    QString envType = resource["envelope"].typeName();
    if ( envType == "Ilwis::Box<double>" || envType == "Ilwis::Envelope") {
        bounds = resource["envelope"].value<Envelope>();
    }else if (QString(resource["envelope"].typeName()) == "QString" &&
              resource["envelope"].toString() != sUNDEF) {
        bounds = Envelope(resource["envelope"].toString());
    }
    if ( bounds.isValid()) {
        coverage->envelope(bounds);
    }
    if ( resource.ilwisType() == itRASTER) {
        IDomain dom;
        QString tpname = resource["domain"].typeName();
        if (tpname == "Ilwis::IDomain")
            dom = resource["domain"].value<Ilwis::IDomain>();
        else if( tpname == "QString" &&
                 resource["domain"].toString() != sUNDEF  ) {
            Resource newresource = resource.property2Resource("domain", itDOMAIN);
            if ( newresource.isValid()) {
                if (!dom.prepare(newresource, options))
                    return false;
            }
        } else if ( tpname == "qulonglong"){
            if(!dom.prepare(resource["domain"].value<quint64>()))
                return 0;
        }

        if ( dom.isValid()){
            RasterCoverage *raster = static_cast<RasterCoverage *>(coverage);
            raster->datadefRef().domain(dom);
        }
    }
    return true;
}
bool RasterCoverageConnector::store(IlwisObject *obj, const IOOptions & )
{
    if(!loadDriver())
        return false;

    RasterCoverage *raster = static_cast<RasterCoverage *>(obj);

    DataDefinition currentDef = raster->datadefRef();
    if (! hasType(raster->datadef().domain()->ilwisType(),itNUMERICDOMAIN | itCOLORDOMAIN)){
        IDomain dom;
        QString code = raster->datadef().domain()->ilwisType() == itITEMDOMAIN ? "code=count" : "code=value";
        if(!dom.prepare(code)) { //TODO:  for the moment only value maps in gdal
            return ERROR1(ERR_NO_INITIALIZED_1,obj->name());
        }
        currentDef.domain(dom);
    }
    Size<> sz = raster->size();
    GDALDataType gdalType = ilwisType2GdalType(currentDef.range()->valueType());
    QString filename = constructOutputName(_driver);
    bool isColorMap = currentDef.domain()->ilwisType() == itCOLORDOMAIN;
    bool ispaletteMap = currentDef.domain()->valueType() == itPALETTECOLOR;

    GDALDatasetH dataset = 0;
    if ( ispaletteMap && format() == "GTiff"){
        char *options[] = {"PHOTOMETRIC=PALETTE", NULL};
        dataset = gdal()->create( _driver, filename.toLocal8Bit(), sz.xsize(), sz.ysize(),  sz.zsize(), gdalType, options );
    }else
        dataset = gdal()->create( _driver, filename.toLocal8Bit(), sz.xsize(), sz.ysize(),  isColorMap ?  sz.zsize() * 3 : sz.zsize(), gdalType, 0 );
    if ( dataset == 0) {
        return ERROR2(ERR_COULDNT_CREATE_OBJECT_FOR_2, "data set",_fileUrl.toLocalFile());
    }
    bool ok = setGeotransform(raster, dataset);
    if (ok)
        ok = setSRS(raster, dataset);

    if (!ok)
        return false;

    if ( isColorMap ){
        ok = storeColorRaster(raster, dataset)    ;
    } else {
        switch(gdalType) {
        case GDT_Byte:
            ok = save<quint8>(raster, dataset,gdalType);break;
        case GDT_UInt16:
            ok = save<quint16>(raster, dataset,gdalType);break;
        case GDT_Int16:
            ok = save<qint16>(raster, dataset,gdalType);break;
        case GDT_Int32:
            ok = save<qint32>(raster, dataset,gdalType);break;
        case GDT_UInt32:
            ok = save<quint32>(raster, dataset,gdalType);break;
        case GDT_Float32:
            ok = save<float>(raster, dataset,gdalType);break;
        case GDT_Float64:
            ok = save<double>(raster, dataset,gdalType);break;
        default:
            ok= ERROR1(ERR_NO_INITIALIZED_1, "gdal Data type");
        }
    }

    gdal()->close(dataset);

    return ok;
}