// check for identical dictionary content, regardless of the order
bool checkDictionaryContent(const dictionary& dict1, const dictionary& dict2)
{
    // trivial cases first
    if (&dict1 == &dict2)
    {
        return true;
    }
    else if (dict1.size() != dict2.size())
    {
        return false;
    }


    forAllConstIter(dictionary, dict1, iter1)
    {
        const entry* entryPtr = dict2.lookupEntryPtr
        (
            iter1().keyword(),
            false,
            false
        );

        if (!entryPtr)
        {
            return false;
        }

        const entry& entry1 = iter1();
        const entry& entry2 = *entryPtr;

        bool ok = false;
        if (entry1.isDict())
        {
            if (entry2.isDict())
            {
                ok = checkDictionaryContent(entry1.dict(), entry2.dict());
            }
        }
        else
        {
            ok = (entry1 == entry2);
        }


        if (!ok)
        {
            return false;
        }
    }

    return true;
}
    GeoResource::GeoResource(int xsz, int ysz, int bsz, GDALDataType datatype, string filename, dictionary options)
        : _Filename(filename) {

        // format, driver, and file extension
        string format = Options::DefaultFormat();
        //if (format == "GTiff") options["COMPRESS"] = "LZW";
        GDALDriver *driver = GetGDALDriverManager()->GetDriverByName(format.c_str());
        // TODO check for null driver and create method
        // Check extension
        string ext = driver->GetMetadataItem(GDAL_DMD_EXTENSION);
        if (ext != "" && _Filename.extension().string() != ('.'+ext)) _Filename = boost::filesystem::path(_Filename.string() + '.' + ext);

        // add options
        char **papszOptions = NULL;
        if (options.size()) {
            for (dictionary::const_iterator imap=options.begin(); imap!=options.end(); imap++)
                papszOptions = CSLSetNameValue(papszOptions,imap->first.c_str(),imap->second.c_str());
        }

        // create file
        //BOOST_LOG_TRIVIAL(info) << Basename() << ": create new file " << xsz << " x " << ysz << " x " << bsz << std::endl;
        if (Options::Verbose() > 4)
            std::cout << Basename() << ": create new file " << xsz << " x " << ysz << " x " << bsz << std::endl;
        _GDALDataset.reset( driver->Create(_Filename.string().c_str(), xsz,ysz,bsz,datatype, papszOptions) );
        if (_GDALDataset.get() == NULL) {
            //BOOST_LOG_TRIVIAL(fatal) << "Error creating " << _Filename.string() << CPLGetLastErrorMsg() << std::endl;
            std::cout << "Error creating " << _Filename.string() << CPLGetLastErrorMsg() << std::endl;
        }
    }
Foam::searchableSurfaces::searchableSurfaces
(
    const IOobject& io,
    const dictionary& topDict
)
:
    PtrList<searchableSurface>(topDict.size()),
    names_(topDict.size()),
    regionNames_(topDict.size()),
    allSurfaces_(identity(topDict.size()))
{
    label surfI = 0;
    forAllConstIter(dictionary, topDict, iter)
    {
        const word& key = iter().keyword();

        if (!topDict.isDict(key))
        {
            FatalErrorIn
            (
                "searchableSurfaces::searchableSurfaces"
                "( const IOobject&, const dictionary&)"
            )   << "Found non-dictionary entry " << iter()
                << " in top-level dictionary " << topDict
                << exit(FatalError);
        }

        const dictionary& dict = topDict.subDict(key);

        names_[surfI] = key;
        dict.readIfPresent("name", names_[surfI]);

        // Make IOobject with correct name
        autoPtr<IOobject> namedIO(io.clone());
        // Note: we would like to e.g. register triSurface 'sphere.stl' as
        // 'sphere'. Unfortunately
        // no support for having object read from different location than
        // their object name. Maybe have stlTriSurfaceMesh which appends .stl
        // when reading/writing?
        namedIO().rename(key);  // names_[surfI]

        // Create and hook surface
        set
        (
            surfI,
            searchableSurface::New
            (
                dict.lookup("type"),
                namedIO(),
                dict
            )
        );
        const searchableSurface& s = operator[](surfI);

        // Construct default region names by prepending surface name
        // to region name.
        const wordList& localNames = s.regions();

        wordList& rNames = regionNames_[surfI];
        rNames.setSize(localNames.size());

        forAll(localNames, regionI)
        {
            rNames[regionI] = names_[surfI] + '_' + localNames[regionI];
        }

        // See if dictionary provides any global region names.
        if (dict.found("regions"))
        {
            const dictionary& regionsDict = dict.subDict("regions");

            forAllConstIter(dictionary, regionsDict, iter)
            {
                const word& key = iter().keyword();

                if (regionsDict.isDict(key))
                {
                    // Get the dictionary for region iter.keyword()
                    const dictionary& regionDict = regionsDict.subDict(key);

                    label index = findIndex(localNames, key);

                    if (index == -1)
                    {
                        FatalErrorIn
                        (
                            "searchableSurfaces::searchableSurfaces"
                            "( const IOobject&, const dictionary&)"
                        )   << "Unknown region name " << key
                            << " for surface " << s.name() << endl
                            << "Valid region names are " << localNames
                            << exit(FatalError);
                    }

                    rNames[index] = word(regionDict.lookup("name"));
                }
            }
        }

        surfI++;
    }
void Foam::GeometricField<Type, PatchField, GeoMesh>::Boundary::
readField
(
    const DimensionedField<Type, GeoMesh>& field,
    const dictionary& dict
)
{
    // Clear the boundary field if already initialised
    this->clear();

    this->setSize(bmesh_.size());

    if (debug)
    {
        InfoInFunction << endl;
    }


    label nUnset = this->size();

    // 1. Handle explicit patch names. Note that there can be only one explicit
    //    patch name since is key of dictionary.
    forAllConstIter(dictionary, dict, iter)
    {
        if (iter().isDict() && !iter().keyword().isPattern())
        {
            label patchi = bmesh_.findPatchID(iter().keyword());

            if (patchi != -1)
            {
                this->set
                (
                    patchi,
                    PatchField<Type>::New
                    (
                        bmesh_[patchi],
                        field,
                        iter().dict()
                    )
                );
                nUnset--;
            }
        }
    }

    if (nUnset == 0)
    {
        return;
    }


    // 2. Patch-groups. (using non-wild card entries of dictionaries)
    // (patchnames already matched above)
    // Note: in reverse order of entries in the dictionary (last
    // patchGroups wins). This is so is consistent with dictionary wildcard
    // behaviour
    if (dict.size())
    {
        for
        (
            IDLList<entry>::const_reverse_iterator iter = dict.rbegin();
            iter != dict.rend();
            ++iter
        )
        {
            const entry& e = iter();

            if (e.isDict() && !e.keyword().isPattern())
            {
                const labelList patchIDs = bmesh_.findIndices
                (
                    e.keyword(),
                    true                    // use patchGroups
                );

                forAll(patchIDs, i)
                {
                    label patchi = patchIDs[i];

                    if (!this->set(patchi))
                    {
                        this->set
                        (
                            patchi,
                            PatchField<Type>::New
                            (
                                bmesh_[patchi],
                                field,
                                e.dict()
                            )
                        );
                    }
                }
            }
        }
    }