/**
 * feed-atom.js
 * Copyright (c) 2000 - 2017 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Contact:
 * Sungmin Kim <sm.art.kim@samsung.com>
 * Jonghwan Park <iwin100.park@samsung.com>
 * Kitae Kim <kt920.kim@samsung.com>
 *
 * 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.
 *
 * Contributors:
 * - S-Core Co., Ltd
**/

var fs = require('fs');
var uuid = require('node-uuid');
var xml = require('xml');
var _ = require('underscore');
var FeedParser = require('feedparser');

module.exports = Feed;
function Feed(title) {
    var self = this;

    this.title = title;
    this.id = 'uuid:' + uuid.v4();
    this.entryList = [];

    this.set = function (key, value) {
        self[key] = value;
    };

    this.get = function (key) {
        return self[key];
    };

    this.load = function (filePath, callback) {
        self.title = '';
        self.id = '';
        self.entryList = [];

        fs.createReadStream(filePath)
            .on('error', callback)
            .pipe(new FeedParser())
            .on('error', callback)
            .on('meta', function (meta) {
                self.title = meta.title;
                self.id = meta['atom:id']['#'];
                self.updated = meta['atom:updated']['#'];
            })
            .on('readable', function () {
                var stream = this;
                var item;
                while (true) {
                    item = stream.read();
                    if (!item) {
                        break;
                    }

                    var entryObj = {
                        id: item.guid,
                        title: item.title,
                        published: item['atom:published']['#'],
                        updated: item['atom:updated']['#'],
                        content: item['atom:content']['@']['src'],
                        version: item['atom:vsix']['version']['#']
                    };

                    if (_.isArray(item['atom:author'])) {
                        entryObj.author = _.map(item['atom:author'], function (a) {
                            return a['name']['#'];
                        });
                    } else {
                        entryObj.author = [];
                        entryObj.author.push(item['atom:author']['name']['#']);
                    }

                    if (item['summary']) {
                        entryObj.summary = item.summary;
                    }

                    if (item['atom:link']) {
                        _.each(item['atom:link'], function (link) {
                            if (link['@']['rel'] === 'previewimage') {
                                entryObj.previewImage = link['@']['href'];
                            } else if (link['@']['rel'] === 'icon') {
                                entryObj.icon = link['@']['href'];
                            } else {
                                // ignore
                            }
                        });
                    }
                    self.entryList.push(entryObj);
                }
            })
            .on('end', callback);
    };

    /**
     * add entry information
     * @param entry = { id: {string}  //  entry id
     *                  title: {string} // entry title
     *                  summary: {string} // entry summary
     *                  published: {string} // published date ex) 2017-01-25T21:25:48Z
     *                  author: [{string}]  // author  ex) [ 'jh', 'kt', 'sm' ]
     *                  previewImage: {string} // previewImage file path  ex) ./item/1.0/pi.jpg
     *                  icon: {string} // icon file path  ex) ./item/1.0/icon.png
     *                  content: {string} // .vsix file path  ex) ./item/1.0/item.vsix
     *                  version: {string} // .vsix version
     *                }
     */
    this.addEntry = function (entry, callback) {
        entry = entry || {};

        if (!entry.id || !entry.title || !entry.published ||
            !entry.author || !entry.content || !entry.version) {
            return callback(new Error('id, title, published, author, content, version information must be exist'));
        }

        self.entryList.push(entry);
        callback(null);
    };

    this.removeEntry = function (entryId, callback) {
        var index = _.findIndex(self.entryList, function (e) {
            return e.id === entryId;
        });

        if (index === -1) {
            return callback(new Error('Cannot find entry(' + entryId + ')'));
        } else {
            self.entryList.splice(index, 1);
            return callback(null);
        }
    };

    this.updateEntry = function (entry, callback) {
        if (!entry.id || !entry.title || !entry.published ||
            !entry.author || !entry.content || !entry.version) {
            return callback(new Error('id, title, published, author, content, version information must be exist'));
        }

        var index = _.findIndex(self.entryList, function (e) {
            return e.id === entry.id;
        });

        if (index !== -1) {
            self.entryList.splice(index, 1);
        }

        self.entryList.push(entry);
        callback(null);
    };

    /** Returning an array of all the values that contain all of the key-value pairs listed
     *   in condition.
     *   ex) searchEntry( {id: 'myid'}, function(err, output) { console.log(output[0]); } )
     */
    this.searchEntry = function (condition, callback) {
        callback(null, _.where(self.entryList, condition));
    };

    this.save = function (filePath, callback) {
        var feed = [];
        var date = new Date().toISOString();
        var data = '<?xml version="1.0" encoding="utf-8" ?>\n';

        feed.push({ _attr: { xmlns: 'http://www.w3.org/2005/Atom' }});
        feed.push({ title: self.title });
        feed.push({ id: self.id });
        feed.push({ updated: date });

        // entry
        _.each(self.entryList, function (entry) {
            var entryObj = [
                { title: entry.title },
                { id: entry.id },
                { summary: entry.summary },
                { published: entry.published },
                { updated: entry.updated }
            ];

            _.each(entry.author, function (author) {
                var authorList = [];
                authorList.push({ name: author });
                entryObj.push({ author: authorList });
            });

            entryObj.push({
                link: {
                    _attr: {
                        rel: 'icon', type: 'text', href: entry.icon
                    }
                }
            });

            entryObj.push({
                link: {
                    _attr: {
                        rel: 'previewimage', type: 'text', href: entry.previewImage
                    }
                }
            });

            entryObj.push({
                content: {
                    _attr: {
                        type: 'application/octet-stream', src: entry.content
                    }
                }
            });

            entryObj.push({
                Vsix: [
                    { _attr: {
                        'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
                        'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
                        xmlns: 'http://schemas.microsoft.com/developer/vsx-syndication-schema/2010'
                    }},
                    { Version: entry.version },
                    { Id: entry.id }
                ]
            });

            feed.push({ entry: entryObj });
        });

        data += xml({feed: feed}, true);

        fs.writeFile(filePath, data, callback);
    };
}
