/*
 * Copyright 2010-2011 Research In Motion Limited.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var util = require("../utils");

// Removes the start and end slashes from the path
function _trimSurroundingSlashes(path) {
    // Trim starting slash
    if (util.startsWith(path, "/")) {
        path = path.substr(1);
    }

    // Trim ending slash
    if (util.endsWith(path, "/")) {
        path = path.substr(0, path.length - 1);
    }

    return path;
}

// Determines the depth of the given path
// Folder path must not include the scheme or the host
function _determineDepth(folderPath) {
    var depthCount = 0;
    
    // Replace all backslashes with forward slash
    folderPath = folderPath.replace("\\", "/");
    
    // Special case: "/" is the given path
    if (folderPath === "/") {
        return 0;
    }

    folderPath = _trimSurroundingSlashes(folderPath);

    // Count slashes remaining
    while (folderPath.indexOf("/") !== -1) {
        depthCount = depthCount + 1;

        // Add 1 to skip the slash
        folderPath = folderPath.substring(folderPath.indexOf("/") + 1);
    }

    // Add one more for the remaining folder
    depthCount += 1;

    return depthCount;
}

// Parse a folder path up to the desired depth
function _getPath(folderPath, desiredDepth) {   
    var depthCount = 0, builtPath = "";

    // Special case: Desired depth is 0
    if (desiredDepth === 0) {
        return "/";
    }

    // Replace all backslashes with forward slash
    folderPath = folderPath.replace("\\", "/");       

    folderPath = _trimSurroundingSlashes(folderPath);

    // Count slashes remaining
    while (depthCount < desiredDepth) {
        depthCount += 1;
        
        // Add 1 to skip the slash
        builtPath += "/" + folderPath.substring(0, folderPath.indexOf('/'));
        folderPath = folderPath.substring(folderPath.indexOf('/') + 1);
    }

    return builtPath;
}

function WebFolderAccessManager() {
    this._pathCollection = {};
    this._maxPathLength = 0;
}

WebFolderAccessManager.prototype.addAccess = function (folderPath, access) {
    if (!folderPath) {
        folderPath = "/";
    }

    // Trim surrounding slashes for consistency
    // The root "/" is a special case that does not need this trimming
    if (folderPath !== "/") {
        folderPath = "/" + _trimSurroundingSlashes(folderPath);
    }

    folderPath = folderPath.toLowerCase();

    this._pathCollection[folderPath] = access;

    // Determine the depth of the path
    this._maxPathLength = Math.max(this._maxPathLength, _determineDepth(folderPath));
};

WebFolderAccessManager.prototype.getAccess = function (folderPath) {   
    var depth = _determineDepth(folderPath);
    return this.getAccessRecursively(folderPath, depth);
};

WebFolderAccessManager.prototype.fetchAccess = function (folderPath) {
    var queryIndex, folderPathWildcard;

    if (!this._pathCollection.hasOwnProperty(folderPath)) {
        // If there isn't an exact match and folderPath contains query string,
        // check if the path collection contains an access with the same folderPath
        // but with wildcard query
        if ((queryIndex = folderPath.indexOf("?")) > -1) {
            folderPathWildcard = folderPath.slice(0, queryIndex + 1) + "*";

            if (this._pathCollection.hasOwnProperty(folderPathWildcard)) {
                return this._pathCollection[folderPathWildcard];
            }
        }

        return null;
    } else {
        return this._pathCollection[folderPath];
    }
};

WebFolderAccessManager.prototype.getAccessRecursively = function (folderPath, pathLength) {
    var fetchedAccess,
        newPathLength,
        newPath;

    if (!folderPath) {
        return null;
    }

    folderPath = folderPath.toLowerCase();

    if (!!(fetchedAccess = this.fetchAccess(folderPath))) {
        return fetchedAccess;
    } else {
        // Truncate the end portion of the path and try again
        newPathLength = Math.min(this._maxPathLength, pathLength - 1);
        newPath = _getPath(folderPath, newPathLength);

        return this.getAccessRecursively(newPath, newPathLength);
    }
};

function WebFolderAccess() {
    this._mgr = new WebFolderAccessManager();
}

// folderPath - folder path must not include the scheme or the host
WebFolderAccess.prototype.addAccess = function (folderPath, access) {
    this._mgr.addAccess(folderPath, access);
};

// folderPath - folder path must not include the scheme or the host
WebFolderAccess.prototype.getAccess = function (folderPath) {
    return this._mgr.getAccess(folderPath);
};

exports.WebFolderAccess = WebFolderAccess;
