/**
 * fs-repo-api.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
**/

'use strict';

var async = require('async');
var fs = require('fs');
var extfs = require('fs-extra');
var path = require('path');
var _ = require('underscore');

var utils = require('../../../lib/utils.js');
var DError = require('../../../core/exception.js');

var DIST_INFO_FILE = 'distribution.info';

module.exports.createDistribution = createDistribution;
module.exports.removeDistribution = removeDistribution;
module.exports.loadDistributions = loadDistributions;
module.exports.isRepositoryExist = isRepositoryExist;
module.exports.loadDistributionInfoFromString = loadDistributionInfoFromString;

function isRepositoryExist(repoPath, callback) {
    fs.exists(path.join(repoPath, DIST_INFO_FILE), callback);
}

function createDistribution(repo, distribution, callback) {
    var distName = distribution.name;
    var distInfoPath = path.join(repo.path, DIST_INFO_FILE);

    // create default directories of a distribution.
    async.series([
        function (cb) {
            extfs.mkdirp(path.join(repo.path, distName), cb);
        },
        function (cb) {
            fs.mkdir(path.join(repo.path, distName, 'snapshots'), cb);
        },
        function (cb) {
            fs.writeFile(path.join(repo.path, distName, 'snapshot.info'), '', cb);
        },
        function (cb) {
            fs.mkdir(path.join(repo.path, distName, 'binary'), cb);
        },
        function (cb) {
            fs.mkdir(path.join(repo.path, distName, 'changes'), cb);
        },
        function (cb) {
            fs.mkdir(path.join(repo.path, distName, 'source'), cb);
        },
        function (cb) {
            fs.exists(distInfoPath, function (exists) {
                if (exists) {
                    cb(null);
                } else {
                    // initialize distribution.info file.
                    createDistributionInfo(distInfoPath, cb);
                }
            });
        },
        function (cb) {
            updateDistributionInfo(distInfoPath, distribution, cb);
        }
    ],
    function (err) {
        callback(err);
    });
}

function removeDistribution(name, repoPath, callback) {
    async.waterfall([
        function (cb) {
            loadDistributionInfo(repoPath, function (err, dists) {
                cb(err, dists);
            });
        },
        function (dists, cb) {
            var remainDists = _.reject(dists, function (dist) {
                return dist.name === name;
            });

            var lines = [];
            _.each(remainDists, function (dist) {
                lines.push('name : ' + dist.name);
                lines.push('time : ' + dist.time);
                if (dist.uid) {
                    lines.push('id : ' + dist.uid);
                }
                lines.push('');
            });

            fs.writeFile(path.join(repoPath, 'distribution.info'), lines.join('\n'), cb);
        },
        function (cb) {
            utils.removePathIfExist(path.join(repoPath, name), cb);
        }
    ],
    function (err) {
        callback(err);
    });
}

function loadDistributions(repoPath, distName, callback) {
    loadDistributionInfo(path.join(repoPath, DIST_INFO_FILE), function (err, dists) {
        if (err) {
            return callback(new DError('FSREPO001', { repo: repoPath }));
        } else {
            if (dists.length === 0) {
                return callback(new DError('FSREPO002', { repo: repoPath }));
            } else {
                var distributions;
                if (distName) {
                    distributions = _.filter(dists, function (dist) {
                        return dist.name === distName;
                    })[0];
                } else {
                    distributions = dists;
                }
                callback(null, distributions);
            }
        }
    });
}

function loadDistributionInfoFromString(contents, repoPath) {
    var lines = contents.split('\n');

    var dists = [];
    var newDist = {};

    _.each(lines, function (line) {
        var toks = line.split(/[: ]+/);

        if (toks[0] === 'name') {
            if (!_.isEmpty(newDist)) {
                dists.push(newDist);
                newDist = {};
            }

            newDist.name = toks[1];
            if (utils.isURL(repoPath)) {
                newDist.path = repoPath + '/' + newDist.name;
            } else {
                newDist.path = path.join(repoPath, newDist.name);
            }
        } else if (toks[0] === 'time') {
            newDist.time = toks[1];
        } else if (toks[0] === 'id') {
            newDist.uid = toks[1];
        } else {
            // ignore
        }
    });

    if (!_.isEmpty(newDist)) {
        dists.push(newDist);
    }

    return dists;
}

// private functions
function createDistributionInfo(distInfoPath, callback) {
    fs.writeFile(distInfoPath, '', callback);
}

function loadDistributionInfo(distInfoPath, callback) {
    var repoPath = path.dirname(distInfoPath);
    loadDistributionInfoFile(distInfoPath, repoPath, callback);
}

function loadDistributionInfoFile(infoFilePath, repoPath, callback) {
    fs.readFile(infoFilePath, {
        encoding: 'utf8'
    },
    function (err, contents) {
        if (err) {
            return callback(err, null);
        } else {
            return callback(err, loadDistributionInfoFromString(contents, repoPath));
        }
    });
}

function updateDistributionInfo(distInfoPath, distribution, callback) {

    async.waterfall([
        function (cb) {
            loadDistributionInfo(distInfoPath, function (err, distInfo) {
                cb(err, distInfo);
            });
        },
        function (distInfo, cb) {
            var lines = [];

            _.each(distInfo, function (dist) {
                lines.push('name : ' + dist.name);
                lines.push('time : ' + dist.time);
                if (dist.uid) {
                    lines.push('id : ' + dist.uid);
                }
                lines.push('');
            });

            lines.push('name : ' + distribution.name);
            lines.push('time : ' + distribution.time);

            fs.writeFile(distInfoPath, lines.join('\n'), function (err) {
                cb(err);
            });
        }
    ],
    function (err) {
        callback(err);
    });
}
