/*
 * Copyright (c) 2014 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * 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.
 */

/*global console, tizen, define, RegExp*/

/**
 * Content module.
 * @requires {@link core/event}
 * @requires {@link core/filesystem}
 * @namespace MiniGallery/models/content
 * @memberof MiniGallery/models
 * @author Piotr Dabrowski <p.dabrowski2@samsung.com>
 * @author Kamil Stepczuk <k.stepczuk@samsung.com>
 * @author Sergiusz Struminski <s.struminski@samsung.com>
 */
define({
    name: 'models/content',
    requires: [
        'core/event',
        'core/filesystem'
    ],
    def: function content(req) {
        'use strict';

        /**
         * Event module object.
         * @type {Module}
         */
        var e = req.core.event,

            /**
             * Filesystem module object.
             * @type {Module}
             */
            filesystem = req.core.filesystem,

            /**
             * Galleries array.
             * galleries [
             *     gallery {
             *          name:     String,
             *          resource: String,
             *          path:     String,
             *          images: [
             *              ImageContent,
             *              ...
             *          ]
             *     },
             *     ...
             * ]
             * In the galleries array ImageContent objects are extended
             * with 'path', 'resource' and 'directory' attributes.
             * Gallery can also be obtained from the galleries array object
             * by its path with the [] operator.
             * @type {array}
             */
            galleries = [],

            /**
             * Flag indicating if galleries array is refreshed.
             * @type {boolean}
             */
            refreshed = false,

            /**
             * Filter for images.
             * @type {tizen.AttributeFilter}
             */
            filter = new tizen.AttributeFilter(
                'type',
                'EXACTLY',
                'IMAGE'
            ),

            /**
             * Sorting alphabetically mode.
             * @type {tizen.SortMode}
             */
            sortMode = new tizen.SortMode(
                'title',
                'ASC'
            ),
            /**
             * Resource path to media.
             * @type {string}
             */
            RESOURCE_PATH = '/opt/usr/media/';

        /**
         * Extracts path data.
         * @param {string} fileUri
         * @return {{
         * name: string,
         * path: string,
         * resource: string,
         * directory: string}}
         */
        function extractPathData(fileUri) {
            var filepath = '',
                parts = [],
                name = '',
                path = '',
                resource = '',
                directory = '';
            filepath = fileUri.replace('file://', ''); // file path from URI
            parts = filepath.split('/'); // split the path
            // get filename and remove it from the path parts
            name = parts.pop();
            directory = parts[parts.length - 1]; // get directory name
            path = parts.join('/'); // get directory path
            resource = path.replace(RESOURCE_PATH, ''); // resource path
            resource = resource.replace(
                new RegExp('^[^\/]+'),
                function lowerText(text) {
                    return text.toLowerCase();
                }
            );
            return {
                name: name,
                path: path,
                resource: resource,
                directory: directory
            };
        }

        /**
         * Content find success callback.
         * @param {object} [data]
         * @param {array} items
         */
        function contentFindSuccess(data, items) {
            var length = items.length,
                i = 0,
                item = null,
                pathdata = null;

            // clear the galleries array
            galleries = [];
            // fill galleries array with new images
            for (i = 0; i < length; i += 1) {
                item = items[i];
                pathdata = extractPathData(item.contentURI);
                item.path = pathdata.path;
                item.resource = pathdata.resource;
                item.directory = pathdata.directory;
                if (galleries[pathdata.path] === undefined) {
                    galleries[pathdata.path] = {
                        name: pathdata.directory,
                        resource: pathdata.resource,
                        path: pathdata.path,
                        images: []
                    };
                    galleries.push(galleries[pathdata.path]);
                }
                galleries[pathdata.path].images.push(item);
            }
            // sort the galleries array by gallery name
            galleries.sort(
                function sort(g1, g2) {
                    var n1 = g1.name.toLowerCase(),
                        n2 = g2.name.toLowerCase();
                    if (n1 < n2) {
                        return -1;
                    }
                    if (n1 > n2) {
                        return 1;
                    }
                    return 0;
                }
            );
            // done
            refreshed = true;
            e.fire('refreshed', data);
        }

        /**
         * Content find fail callback.
         * @fires "content.refreshFailed"
         * @param {WebAPIError} error
         */
        function contentFindError(error) {
            galleries.length = 0;
            console.warn('Content API find() failed!', error);
            e.fire('refresh.failed', error);
        }

        /**
         * Refreshes galleries.
         * @param {object} [data]
         */
        function refreshGalleries(data) {
            refreshed = false;
            tizen.content.find(
                contentFindSuccess.bind(null, data),
                contentFindError,
                null,
                filter,
                sortMode
            );
        }

        /**
         * Returns galleries array.
         * @memberof MiniGallery/models/content
         * @return {array}
         */
        function getGalleries() {
            return galleries;
        }

        /**
         * Returns true if galleries array is refreshed,
         * false otherwise.
         * @memberof MiniGallery/models/content
         * @return {boolean}
         */
        function isRefreshed() {
            return refreshed;
        }

        /**
         * Scans a file with given fileUri to create or update content
         * in the content database.
         * @param {string} fileUri
         */
        function scanFile(fileUri) {
            try {
                tizen.content.scanFile(
                    fileUri,
                    null,
                    function onScanFileError(error) {
                        console.error('scanFile ERROR: ', error.message);
                    }
                );
            } catch (error) {
                console.error('scanFile ERROR: ', error.message);
            }
        }

        /**
         * Deletes specified file.
         * @memberof MiniGallery/models/content
         * @param {string} fileUri
         */
        function deleteFile(fileUri) {
            filesystem.deleteNode(
                fileUri,
                scanFile.bind(null, fileUri)
            );
        }

        /**
         * Registers content listeners
         */
        function addContentListeners() {
            tizen.content.setChangeListener({
                oncontentadded: function onContentAdded() {
                    refreshGalleries({
                        reason: 'added'
                    });
                },
                oncontentupdated: function onContentUpdated() {
                    refreshGalleries({
                        reason: 'updated'
                    });
                },
                oncontentremoved: function onContentRemoved(id) {
                    refreshGalleries({
                        reason: 'removed',
                        id: id
                    });
                }
            });
        }

        /**
         * Initializes the module.
         * @memberof MiniGallery/models/content
         */
        function init() {
            refreshGalleries();
            addContentListeners();
        }

        // return public functions of Content object
        return {
            init: init,
            deleteFile: deleteFile,
            isRefreshed: isRefreshed,
            getGalleries: getGalleries
        };

    }
});
