'use strict';
exports.__esModule = true;
var cheerio = require("cheerio");
var fs = require("fs");
var mkdirp = require("mkdirp");
var my_request = require("./my_request");
var path = require("path");
var index_1 = require("./subtitle/index");
var index_2 = require("./video/index");
var xml2js = require("xml2js");
var log = require("./log");
/**
 * Streams the episode to disk.
 */
function default_1(config, address, done) {
    scrapePage(config, address, function (err, page) {
        if (err) {
            return done(err, false);
        }
        scrapePlayer(config, address, page.id, function (errS, player) {
            if (errS) {
                return done(errS, false);
            }
            download(config, page, player, done);
        });
    });
}
exports["default"] = default_1;
/**
 * Completes a download and writes the message with an elapsed time.
 */
function complete(epName, message, begin, done) {
    var timeInMs = Date.now() - begin;
    var seconds = prefix(Math.floor(timeInMs / 1000) % 60, 2);
    var minutes = prefix(Math.floor(timeInMs / 1000 / 60) % 60, 2);
    var hours = prefix(Math.floor(timeInMs / 1000 / 60 / 60), 2);
    log.dispEpisode(epName, message + ' (' + hours + ':' + minutes + ':' + seconds + ')', true);
    done(null, false);
}
/**
 * Check if a file exist..
 */
function fileExist(path) {
    try {
        fs.statSync(path);
        return true;
    }
    catch (e) {
        return false;
    }
}
function sanitiseFileName(str) {
    return str.replace(/[\/':\?\*"<>\.]/g, '_');
}
/**
 * Downloads the subtitle and video.
 */
function download(config, page, player, done) {
    var series = config.series || page.series;
    series = sanitiseFileName(series);
    var fileName = sanitiseFileName(name(config, page, series, ''));
    var filePath = path.join(config.output || process.cwd(), series, fileName);
    if (fileExist(filePath + '.mkv')) {
        var count = 0;
        if (config.rebuildcrp) {
            log.warn('Adding \'' + fileName + '\' to the DB...');
            return done(null, false);
        }
        log.warn('File \'' + fileName + '\' already exist...');
        do {
            count = count + 1;
            fileName = sanitiseFileName(name(config, page, series, '-' + count));
            filePath = path.join(config.output || process.cwd(), series, fileName);
        } while (fileExist(filePath + '.mkv'));
        log.warn('Renaming to \'' + fileName + '\'...');
        config.filename = fileName;
    }
    if (config.rebuildcrp) {
        log.warn('Ignoring \'' + fileName + '\' as it does not exist...');
        return done(null, true);
    }
    mkdirp(path.dirname(filePath), function (errM) {
        if (errM) {
            return done(errM, false);
        }
        log.dispEpisode(fileName, 'Fetching...', false);
        downloadSubtitle(config, player, filePath, function (errDS) {
            if (errDS) {
                return done(errDS, false);
            }
            var now = Date.now();
            if (player.video.file !== undefined) {
                log.dispEpisode(fileName, 'Fetching video...', false);
                downloadVideo(config, page, player, filePath, function (errDV) {
                    if (errDV) {
                        return done(errDV, false);
                    }
                    if (config.merge) {
                        return complete(fileName, 'Finished!', now, done);
                    }
                    var isSubtited = Boolean(player.subtitle);
                    log.dispEpisode(fileName, 'Merging...', false);
                    index_2["default"].merge(config, isSubtited, player.video.file, filePath, player.video.mode, config.verbose, function (errVM) {
                        if (errVM) {
                            return done(errVM, false);
                        }
                        complete(fileName, 'Finished!', now, done);
                    });
                });
            }
            else {
                log.dispEpisode(fileName, 'Ignoring: not released yet', true);
                done(null, true);
            }
        });
    });
}
/**
 * Saves the subtitles to disk.
 */
function downloadSubtitle(config, player, filePath, done) {
    var enc = player.subtitle;
    if (!enc) {
        return done();
    }
    index_1["default"].decode(enc.id, enc.iv, enc.data, function (errSD, data) {
        if (errSD) {
            return done(errSD);
        }
        var formats = index_1["default"].formats;
        var format = formats[config.format] ? config.format : 'ass';
        formats[format](data, function (errF, decodedSubtitle) {
            if (errF) {
                return done(errF);
            }
            fs.writeFile(filePath + '.' + format, '\ufeff' + decodedSubtitle, done);
        });
    });
}
/**
 * Streams the video to disk.
 */
function downloadVideo(config, page, player, filePath, done) {
    index_2["default"].stream(player.video.host, player.video.file, page.swf, filePath, path.extname(player.video.file), player.video.mode, config.verbose, done);
}
/**
 * Names the file based on the config, page, series and tag.
 */
function name(config, page, series, extra) {
    var episodeNum = parseInt(page.episode, 10);
    var volumeNum = parseInt(page.volume, 10);
    var episode = (episodeNum < 10 ? '0' : '') + page.episode;
    var volume = (volumeNum < 10 ? '0' : '') + page.volume;
    var tag = config.tag || 'CrunchyRoll';
    if (!config.filename) {
        return page.series + ' - s' + volume + 'e' + episode + ' - [' + tag + ']' + extra;
    }
    return config.filename
        .replace(/{EPISODE_ID}/g, page.id.toString())
        .replace(/{EPISODE_NUMBER}/g, episode)
        .replace(/{SEASON_NUMBER}/g, volume)
        .replace(/{VOLUME_NUMBER}/g, volume)
        .replace(/{SEASON_TITLE}/g, page.season)
        .replace(/{VOLUME_TITLE}/g, page.season)
        .replace(/{SERIES_TITLE}/g, series)
        .replace(/{EPISODE_TITLE}/g, page.title)
        .replace(/{TAG}/g, tag) + extra;
}
/**
 * Prefixes a value.
 */
function prefix(value, length) {
    var valueString = (typeof value !== 'string') ? String(value) : value;
    while (valueString.length < length) {
        valueString = '0' + valueString;
    }
    return valueString;
}
/**
 * Requests the page data and scrapes the id, episode, series and swf.
 */
function scrapePage(config, address, done) {
    var epId = parseInt((address.match(/[0-9]+$/) || ['0'])[0], 10);
    if (!epId) {
        return done(new Error('Invalid address.'));
    }
    my_request.get(config, address, function (err, result) {
        if (err) {
            return done(err);
        }
        var $ = cheerio.load(result);
        var swf = /^([^?]+)/.exec($('link[rel=video_src]').attr('href'));
        var regexp = /\s*([^\n\r\t\f]+)\n?\s*[^0-9]*([0-9][\-0-9.]*)?,?\n?\s\s*[^0-9]*((PV )?[S0-9][P0-9.]*[a-fA-F]?)/;
        var look = $('#showmedia_about_media').text();
        var seasonTitle = $('span[itemprop="title"]').text();
        var episodeTitle = $('#showmedia_about_name').text().replace(/[“”]/g, '');
        var data = regexp.exec(look);
        if (!swf || !data) {
            log.warn('Somethig unexpected in the page at ' + address + ' (data are: ' + look + ')');
            log.warn('Setting Season to ’0’ and episode to ’0’...');
            done(null, {
                episode: '0',
                id: epId,
                series: seasonTitle,
                season: seasonTitle,
                title: episodeTitle,
                swf: swf[1],
                volume: '0'
            });
        }
        else {
            done(null, {
                episode: data[3],
                id: epId,
                series: data[1],
                season: seasonTitle,
                title: episodeTitle,
                swf: swf[1],
                volume: data[2] || '1'
            });
        }
    });
}
/**
 * Requests the player data and scrapes the subtitle and video data.
 */
function scrapePlayer(config, address, id, done) {
    var url = address.match(/^(https?:\/\/[^\/]+)/);
    if (!url) {
        return done(new Error('Invalid address.'));
    }
    my_request.post(config, {
        form: {
            current_page: address,
            video_format: config.video_format,
            video_quality: config.video_quality,
            media_id: id
        },
        url: url[1] + '/xml/?req=RpcApiVideoPlayer_GetStandardConfig&media_id=' + id
    }, function (err, result) {
        if (err) {
            return done(err);
        }
        xml2js.parseString(result, {
            explicitArray: false,
            explicitRoot: false
        }, function (errPS, player) {
            if (errPS) {
                return done(errPS);
            }
            try {
                var isSubtitled = Boolean(player['default:preload'].subtitle);
                var streamMode = 'RTMP';
                if (player['default:preload'].stream_info.host === '') {
                    streamMode = 'HLS';
                }
                done(null, {
                    subtitle: isSubtitled ? {
                        data: player['default:preload'].subtitle.data,
                        id: parseInt(player['default:preload'].subtitle.$.id, 10),
                        iv: player['default:preload'].subtitle.iv
                    } : null,
                    video: {
                        file: player['default:preload'].stream_info.file,
                        host: player['default:preload'].stream_info.host,
                        mode: streamMode
                    }
                });
            }
            catch (parseError) {
                done(parseError);
            }
        });
    });
}
//# sourceMappingURL=episode.js.map