bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection *connection, const QUrl &url) {
    if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == SETTINGS_PATH) {
        // this is a POST operation to change one or more settings
        QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent());
        QJsonObject postedObject = postedDocument.object();
        
        // we recurse one level deep below each group for the appropriate setting
        recurseJSONObjectAndOverwriteSettings(postedObject, _settingsMap, _descriptionArray);
        
        // store whatever the current _settingsMap is to file
        persistToFile();
        
        // return success to the caller
        QString jsonSuccess = "{\"status\": \"success\"}";
        connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json");
        
        // defer a restart to the domain-server, this gives our HTTPConnection enough time to respond
        const int DOMAIN_SERVER_RESTART_TIMER_MSECS = 1000;
        QTimer::singleShot(DOMAIN_SERVER_RESTART_TIMER_MSECS, qApp, SLOT(restart()));
        
        return true;
    } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == SETTINGS_PATH) {
        // setup a JSON Object with descriptions and non-omitted settings
        const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions";
        const QString SETTINGS_RESPONSE_VALUE_KEY = "values";
        
        QJsonObject rootObject;
        rootObject[SETTINGS_RESPONSE_DESCRIPTION_KEY] = _descriptionArray;
        rootObject[SETTINGS_RESPONSE_VALUE_KEY] = responseObjectForType("", true);
        
        connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json");
    }
    
    return false;
}
void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
                                                                        QVariantMap& settingsVariant,
                                                                        QJsonObject descriptionObject) {
    foreach(const QString& key, postedObject.keys()) {

        QJsonValue rootValue = postedObject[key];
        
        // we don't continue if this key is not present in our descriptionObject
        if (descriptionObject.contains(key)) {
            if (rootValue.isString()) {
                settingsVariant[key] = rootValue.toString();
            } else if (rootValue.isBool()) {
                settingsVariant[key] = rootValue.toBool();
            } else if (rootValue.isObject()) {
                // there's a JSON Object to explore, so attempt to recurse into it
                QJsonObject nextDescriptionObject = descriptionObject[key].toObject();
                
                if (nextDescriptionObject.contains(DESCRIPTION_SETTINGS_KEY)) {
                    if (!settingsVariant.contains(key)) {
                        // we don't have a map below this key yet, so set it up now
                        settingsVariant[key] = QVariantMap();
                    }
                    
                    recurseJSONObjectAndOverwriteSettings(rootValue.toObject(),
                                                          *reinterpret_cast<QVariantMap*>(settingsVariant[key].data()),
                                                          nextDescriptionObject[DESCRIPTION_SETTINGS_KEY].toObject());
                }
            }
        }
    }
}
bool DomainServerSettingsManager::handleHTTPRequest(HTTPConnection* connection, const QUrl &url) {
    if (connection->requestOperation() == QNetworkAccessManager::PostOperation && url.path() == "/settings.json") {
        // this is a POST operation to change one or more settings
        QJsonDocument postedDocument = QJsonDocument::fromJson(connection->requestContent());
        QJsonObject postedObject = postedDocument.object();
        
        // we recurse one level deep below each group for the appropriate setting
        recurseJSONObjectAndOverwriteSettings(postedObject, _settingsMap, _descriptionObject);
        
        // store whatever the current _settingsMap is to file
        persistToFile();
        
        // return success to the caller
        QString jsonSuccess = "{\"status\": \"success\"}";
        connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json");
        
        return true;
    } else if (connection->requestOperation() == QNetworkAccessManager::GetOperation && url.path() == "/settings.json") {
        // this is a GET operation for our settings
        
        // check if there is a query parameter for settings affecting a particular type of assignment
        const QString SETTINGS_TYPE_QUERY_KEY = "type";
        QUrlQuery settingsQuery(url);
        QString typeValue = settingsQuery.queryItemValue(SETTINGS_TYPE_QUERY_KEY);
        
        QJsonObject responseObject;
        
        if (typeValue.isEmpty()) {
            // combine the description object and our current settings map
            responseObject["descriptions"] = _descriptionObject;
            responseObject["values"] = QJsonDocument::fromVariant(_settingsMap).object();
        } else {
            // convert the string type value to a QJsonValue
            QJsonValue queryType = QJsonValue(typeValue.toInt());
            
            const QString AFFECTED_TYPES_JSON_KEY = "assignment-types";
            
            // enumerate the groups in the description object to find which settings to pass
            foreach(const QString& group, _descriptionObject.keys()) {
                QJsonObject groupObject = _descriptionObject[group].toObject();
                QJsonObject groupSettingsObject = groupObject[DESCRIPTION_SETTINGS_KEY].toObject();
                
                QJsonObject groupResponseObject;
                
                
                foreach(const QString& settingKey, groupSettingsObject.keys()) {
                    QJsonObject settingObject = groupSettingsObject[settingKey].toObject();
                    
                    QJsonArray affectedTypesArray = settingObject[AFFECTED_TYPES_JSON_KEY].toArray();
                    if (affectedTypesArray.isEmpty()) {
                        affectedTypesArray = groupObject[AFFECTED_TYPES_JSON_KEY].toArray();
                    }
                    
                    if (affectedTypesArray.contains(queryType)) {
                        // this is a setting we should include in the responseObject
                        
                        // we need to check if the settings map has a value for this setting
                        QVariant variantValue;
                        QVariant settingsMapGroupValue = _settingsMap.value(group);
                        
                        if (!settingsMapGroupValue.isNull()) {
                            variantValue = settingsMapGroupValue.toMap().value(settingKey);
                        }
                        
                        if (variantValue.isNull()) {
                            // no value for this setting, pass the default
                            groupResponseObject[settingKey] = settingObject[SETTING_DEFAULT_KEY];
                        } else {
                            groupResponseObject[settingKey] = QJsonValue::fromVariant(variantValue);
                        }
                    }
                }
                
                if (!groupResponseObject.isEmpty()) {
                    // set this group's object to the constructed object
                    responseObject[group] = groupResponseObject;
                }
            }
            
        }
        
        connection->respond(HTTPConnection::StatusCode200, QJsonDocument(responseObject).toJson(), "application/json");
        return true;
    }
    
    return false;
}