'use strict';

/**
 * Module dependencies.
 */
var path = require('path');
var fs = require('fs-extra');
var multer = require('multer');
var uuid = require('node-uuid');

var resError = require('./error');
var db = require('../../config/sequelize');
var config = require('../../config/config');
var winston = require('../../config/winston');

/**
 * this function is the middleware that is used to upload a file to the server
 */
var upload = multer({dest: config.root + '/public/resources/', fileFilter: function(req, file, cb){
    if (!file)
        return cb(new Error("file not found"));
    if (file.mimetype === 'audio/mp3' ||
        file.mimetype === 'audio/wav' ||
        file.mimetype === 'image/png' ||
        file.mimetype === 'image/jpeg' ||
        file.mimetype === 'image/pjpg' ||
        file.mimetype === 'image/jpg'){
        return cb(null, true);
    }
    return cb(new Error("invalid type"));
}}).single('resource');

/**
 * this function is used to check if all the information of the incoming file is valid and have the good format
 * @param req
 * @param res
 * @param next
 */
var uploadService = function (req, res, next) {
    upload(req, res, function (err) {
        if (err) {
            winston.error('something went wrong',err.message);
            // An error occurred when uploading
            return resError.UnsupportedMediaType(res, err.message);
        }
        if (!req.file){
            return resError.InternalServerError(res, "no file sent");
        }
        req.file.path = path.join('/resources/' + req.file.filename);
        req.file.original_name = req.file.originalname;
        db.Resource.create(req.file)
            .then(function(resource){
                req.resource = resource;
                winston.info('Succesfully created.');
                resource.addUser(req.user).then(function () {
                    return next();
                });
            }).catch(function(err){
            // TODO delete file if something went wrong
            winston.error(err);
            return resError.InternalServerError(res, err);
        });
    });

};

/**
 * not implemented yet
 * this function is used to clean the server of the unused files
 * @type {exports.deleteService}
 */
var deleteService = module.exports.deleteService = function (_resource) {
    if (_resource.mimetype !== 'application/youtube'){
        winston.info("try delete", _resource.path);
        try{
            fs.removeSync(path.join(config.root, _resource.path));
        }catch(err){
            winston.error(err);
        }
    }
};

module.exports = {
    /**
     * this function try to find an resource by his id
     * if the resource exist the resource is saved into the request and the function next is call
     * else the function return an error
     * @param req
     * @param res
     * @param next
     * @param id
     */
    resource:function(req,res, next, id){
        db.Resource.find({ where: {id: id}}).then(function(_resource){
            if(!_resource) {
                return resError.PreconditionFailed(res, 'Failed to load resource ' + id);
            } else {
                req.resource = _resource;
                return next();
            }
        }).catch(function(err){
            winston.error(err);
            return resError.InternalServerError(res, err);
        });
    },
    /**
     * this function create an resource
     * @param req
     * @param res
     * @returns {*}
     */
    create:function(req,res){
        uploadService(req, res, function () {
            return res.jsonp(req.resource);
        });
    },
    /**
     * this function create an resource
     * @param req
     * @param res
     * @returns {*}
     */
    createYoutube:function(req,res){
        var youtubeResource = {
            original_name:req.query.name,
            size:0,
            filename:req.query.youtube,

            mimetype: 'application/youtube',
            path:req.query.youtube
        };
        db.Resource.create(youtubeResource)
            .then(function(resource){
                req.resource = resource;
                winston.info('Succesfully created.');
                resource.addUser(req.user).then(function () {
                    return res.jsonp(resource);
                });
            }).catch(function(err){
            // TODO delete file if something went wrong
            winston.error(err);
            return resError.InternalServerError(res, err);
        });
    },
    /**
     * this function return all resource from the database
     * @param req
     * @param res
     * @returns {*}
     */
    all:function(req,res){
        db.Resource.findAll().then(function (_resources) {
            return res.jsonp(_resources);
        }).catch(function (err) {
            return resError.InternalServerError(res, err);
        });
    },
    /**
     * this function return one resource (the one into the request)
     * @param req
     * @param res
     * @returns {*}
     */
    show:function(req,res){
        return res.jsonp(req.resource);
    },
    /**
     * this function update information into the resource set into the request
     * @param req
     * @param res
     * @returns {*}
     */
    update:function(req,res){
        req.resource.update(req.body).then(function (resource) {
            return res.jsonp(resource);
        }).catch(function(err){
            return resError.InternalServerError(res, err);
        });
    },
    /**
     * this function delete the resource set into the request
     * @aram req
     * @param res
     * @returns {*}
     */
    delete:function(req,res){
        deleteService(req.resource);
        req.resource.destroy().then(function () {
            return resError.OK(res);
        }).catch(function () {
            return resError.InternalServerError(res, err);
        })
    },
    /**
     * check if the user that make the request is the owner of the resource or if the user is an admin 
     * @param req
     * @param res
     * @param next
     * @returns {*}
     */
    hasAuthorization:function(req, res, next) {
        if (req.user.role === 'admin')
            return next();
        req.resource.getUsers().then(function (_users) {
            for(var i in _users){
                if (_users[i].id === req.user.id){
                    return next();
                }
            }
            return resError.Unauthorized(res, 'User can not access this resource');
        })
    },
    /**
     * all the following functions are used throught the article and alter the resource
     */
    articles:{
        /**
         * show all the articles linked to the current resource
         * @param req
         * @param res
         * @returns {*}
         */
        all:function(req,res){
            req.resource.getArticles().then(function (_articles) {
                return res.jsonp(_articles);
            }).catch(function (err) {
                return resError.InternalServerError(res, err);
            });
        },
        /**
         * Checks if the article is already linked to the resource
         * @param req
         * @param res
         * @param next
         */
        isLinked: function(req, res, next){
            req.article.getResources({where: {id: req.resource.id}}).then(function(foundResources) {
                if (foundResources.length !== 0) {
                    return next();
                }
                return resError.InternalServerError(res, "Resource is not linked to this article.");
            }).catch(function (err) {
                return resError.InternalServerError(res, err);
            });
        },
        /**
         *  Checks if the article is not already linked to the resource
         * @param req
         * @param res
         * @param next
         */
        isNotLinked: function(req, res, next){
            req.article.getResources({where: {id: req.resource.id}}).then(function(foundResources) {
                if (foundResources.length !== 0) {
                    return resError.InternalServerError(res, "Resource is linked to this article.");
                }
                return next();

            }).catch(function (err) {
                return resError.InternalServerError(res, err);
            });
        },

        link: {
            /**
             * assign one article to the current resource
             * @param req
             * @param res
             * @returns {*}
             */
            create: function (req, res) {
                req.resource.addArticle(req.article).then(function (link) {
                    return res.jsonp(link);
                }).catch(function (err) {
                    return resError.InternalServerError(res, err.message);
                });
            },
            /**
             * unassign an article to the current resource
             * @param req
             * @param res
             * @returns {*}
             */
            delete: function (req, res) {
                req.resource.removeArticle(req.article).then(function () {
                    return resError.OK(res);
                }).catch(function (err) {
                    return resError.InternalServerError(res, err);
                });
            }
        }
    },
    /**
     * all the following functions are used throught the exhibition and alter the resource
     */
    exhibitions:{
        /**
         * show all the exhibitions linked to the current resource
         * @param req
         * @param res
         * @returns {*}
         */
        all:function(req,res){
            req.resource.getExhibitions().then(function (_exhibitions) {
                return res.jsonp(_exhibitions);
            }).catch(function (err) {
                return resError.InternalServerError(res, err);
            });
        },
        /**
         *  Checks if the exhibition is already linked to the resource
         * @param req
         * @param res
         * @param next
         */
        isLinked: function(req, res, next){
            req.resource.getExhibitions({where:{id:req.resource.id}}).then(function (_resources) {
                if(_resources.length !== 0){
                    return next();
                }
                return resError.PreconditionFailed(res, "Article is not linked to this Resource.");
            }).catch(function (err) {
                return resError.InternalServerError(res, err);
            });
        },
        /**
         *  Checks if the exhibition is not already linked to the resource
         * @param req
         * @param res
         * @param next
         */
        isNotLinked: function(req, res, next){
            req.resource.getExhibitions({where:{id:req.resource.id}}).then(function (_resources) {
                if(_resources.length !== 0){
                    return resError.PreconditionFailed(res, "Article is linked to this Resource.");
                }
                return next();
            }).catch(function (err) {
                return resError.InternalServerError(res, err);
            });
        },
        link:{
            /**
             * assign one exhibition to the current resource
             * @param req
             * @param res
             * @returns {*}
             */
            create:function(req,res){
                req.resource.setExhibition(req.exhibition).then(function (link) {
                    return res.jsonp(link);
                }).catch(function (err) {
                    return resError.InternalServerError(res, err);
                });
            },
            /**
             * unassign an exhibition to the current resource
             * @param req
             * @param res
             * @returns {*}
             */
            delete:function(req,res){
                req.resource.removeExhibition(req.exhibition).then(function () {
                    return resError.OK(res);
                }).catch(function (err) {
                    return resError.InternalServerError(res, err);
                });
            }
        }
    },
    /**
     * all the following functions are used throught the artist and alter the resource
     */
    artists:{
        /**
         * show all the artists linked to the current resource
         * @param req
         * @param res
         * @returns {*}
         */
        all:function(req,res){
            req.resource.getArtists().then(function (artists) {
                return res.jsonp(artists);
            }).catch(function (err) {
                return resError.InternalServerError(res, err);
            });
        },
        link:{
            /**
             * assign one artist to the current resource
             * @param req
             * @param res
             * @returns {*}
             */
            create:function(req,res){
                req.resource.setArtist(req.artist).then(function (link) {
                    return res.jsonp(link);
                }).catch(function (err) {
                    return resError.InternalServerError(res, err);
                });
            },
            /**
             * unassign an artist to the current resource
             * @param req
             * @param res
             * @returns {*}
             */
            delete:function(req,res){
                deleteService(req.resource);
                req.resource.removeArtist(req.artist).then(function () {
                    return resError.OK(res);
                }).catch(function (err) {
                    return resError.InternalServerError(res, err);
                });
            }
        }
    },
    uploadService: uploadService
};
