/**
 * FeedBlog Generator
 *
 * @copyright 2009 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)
 * @author Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)
 * @since 2009/06/03
 * @version 3.1.0.0
 */
// Feex XMLの<content>要素で、<br>を使用しているか？
var inputValidateMode = 1;
// 出力時に<content>要素に<br>を付加するか否かを格納する変数
var outputValidateMode = 1;
// ログのリストが書かれたXMLのファイルパスを記入してください
var logXmlUrl = "./xml/loglist.xml";

// フィードの基本情報を記録する変数
var feedInfo;
// 記事リストを格納する変数
var entryList;
// 現在編集中の記事の位置を示す変数
var editIndex;
// feedblogの設置アドレスを格納する変数
var pageAddr;
// コンボボックスの横幅を指定します
var comboWidth = 250;

/**
 * 編集中の内容を反映し、画面に出力します
 */
function applyChange(){
    feedInfo = applyFeedinfo();
    pageAddr = feedInfo.alternate;
    
    if (document.getElementById("entry_title").value == "" || document.getElementById("entry_stdin").value == "") {
        if (confirm("タイトルか記事が空白です！FeedBlogでの表示時にエラーが出ますがよろしいですか？") == false) {
            return;
        }
    }
    
    if (editIndex < 0) {
        var entry = new Object();
        var dateRfc3339 = getDate();
        entry.id = pageAddr + "?" + dateRfc3339;
        entry.title = document.getElementById("entry_title").value;
        entry.summary = "";
        entry.published = dateRfc3339;
        entry.updated = dateRfc3339;
        entry.link = pageAddr + "#" + entry.id;
        entry.content = document.getElementById("entry_stdin").value.replace(/\r\n/g, "\n");
        entryList.unshift(entry);
        
        // ログ一覧を更新する
        refleshEntrylistBox();
        
        // 更新後、選択されている項目を、先刻追加した日記に移動する
        document.getElementById("logBox").selectedIndex = 1;
        editIndex = 0;
    }
    else {
        entryList[editIndex].title = document.getElementById("entry_title").value;
        entryList[editIndex].updated = getDate();
        entryList[editIndex].content = document.getElementById("entry_stdin").value.replace(/\r\n/g, "\n");
        
        document.getElementById("logBox").options[parseInt(editIndex) + 1].text = entryList[editIndex].title;
    }
    
    document.getElementById("stdout").value = toXml(feedInfo, entryList);
    
    // プレビューエリアにHTMLを表示します
    document.getElementById("previewArea").innerHTML = entryList[editIndex].content.replace(/\n/g, "<br>");
}

/**
 * mixi用に記事を変換し、ウインドウを立ち上げて表示します
 */
function openMixiWindow(){
    // 日記が選択されていない場合は何もしない
    if (editIndex < 0) {
        return;
    }
    
    // HTMLを生成します
    var window_str = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>FeedBlog Mixi用変換</title><style type="text/css">body {font-size: 12px;line-height: 18px;color: #004488;margin-top: 10px; margin-bottom: 10px;}td.default {font-size: 12px;line-height: 18px;color: #004488;border: 1px solid #8888ff;text-align: left;vertical-align: top;}div {text-align: left;}div.code {background: #f8f8ff;border: 1px solid #c8c8ff;padding: 10px;margin: 10px;margin-left: 0px;border-left: 5px solid #e8e8ff;font-size: 12px;line-height: 18px;}table.pager {padding: 0px;margin: 0px;border: 1px solid #8888ff;}td.pager {border: 1px solid #8888ff;padding-left: 3px;}td.formheader {font-size: 9pt;line-height: 13pt;font-family: sans-serif;font-weight: bold;padding: 3px;border: 1px solid #C5C5DE;background-color: #FAFAFF;}td.forminput {font-size: 9pt;line-height: 13pt;font-family: sans-serif;padding: 5px;border: 1px dotted #C5C5DE;}input {font-size: 9pt;line-height: 13pt;font-family: sans-serif;color: #1E4080;border: 1px dotted #BABAFE;background-color: #F5F5FF;}textarea {font-size: 9pt;line-height: 13pt;font-family: sans-serif;color: #1E4080;border: 1px dotted #BABAFE;background-color: #F5F5FF;}</style></head><body><center><table align="center" style="width: 800px;"><tbody><tr><td class="default" colspan="2" style="padding: 5px; text-align: center; vertical-align: bottom;"><table style="width: 100%"><tbody><tr><td class="formheader" style="text-align: center; width: 100px;">タイトル</td><td class="forminput" style="padding: 0px 5px 0px 3px;"><input type="text" id="entry_title" style="width: 100%" value="' +
    entryList[editIndex].title +
    '"></td></tr><tr><td class="formheader" style="text-align: center;">本文</td><td class="forminput" style="padding: 0px 5px 0px 3px;"><textarea id="entry_stdin" rows="20" style="width: 100%">' +
    mixiWrapper(entryList[editIndex].content) +
    '</textarea></td></tr></tbody></table></td></tr></tbody></table><br><input type="button" value="ウインドウを閉じる" onclick="javascript: window.close();"></center></body></html>';
    
    // ウインドウに書き出します
    var mixi_win = window.open('', 'feedblog_mixi_wrapper', 'width = 850, height = 490, scrollbars=yes');
    mixi_win.document.open();
    mixi_win.document.write(window_str);
    mixi_win.document.close();
}

/**
 * mixi用に通常のHTMLを変換します
 * @param {String} contents 日記の本文が格納されている文字列
 */
function mixiWrapper(contents){
    // 置換に使用する変数
    var target_tag;
    var target_element;
    
    // ニコニコ動画のタグを置換
    while (target_tag = contents.match(/<iframe[^>]*src=["']http:\/\/ext.nicovideo.jp\/thumb\/[A-Za-z]*\d*["'][^>]*>[^<]*<\/iframe>/i)) {
        // src="..."の部分だけ抜き出す
        target_element = target_tag[0].match(/src=["'][^"']*["']/i);
        target_element = '&lt;externalvideo src=&quot;NC:' + target_element[0].replace(/src=["']http:\/\/ext.nicovideo.jp\/thumb\/|["']/ig, "") + ':D&quot;&gt;';
        // iframeタグ全体を置換する
        contents = contents.replace(target_tag, target_element);
    }
    
    // Aタグを変換する
    while (contents.match(/<a[^>]*>/)) {
        // 置換対象のAタグを抽出する
        target_tag = contents.match(/<a[^>]*>/i);
        // href="..."の部分のみを抜き出す
        target_element = target_tag[0].match(/href=["'][^"']*["']/i);
        // 相対URIが検出された場合、フルに置換する
        var baseUri = document.location.href.replace(/[^\/]+$/, '');
        target_element = target_element[0].replace(/\.\//, baseUri).replace(/\.\.\//g, "");
        // Aタグ全体を消去し、再度Aクローズタグの置換を行う
        contents = contents.replace(target_tag, "");
        contents = contents.replace(/<\/a>/i, " ( " + target_element.replace(/href=|["']/g, "") + " ) ");
    }
    
    // ブロック要素のタグが存在した場合、改行をその後に挿入します。
    if (document.getElementById("isCoverBlockTag").checked) {
        contents = contents.replace(/<(div|h\d|p)[^>]*>/ig, "-----------------------------------------------------------------------------\n");
        contents = contents.replace(/(\n|)<\/(div|h\d|p)>/ig, "\n-----------------------------------------------------------------------------\n");
    }
    else {
        contents = contents.replace(/<\/(div|h\d|p)>/ig, "\n");
    }
    
    // 通常のタグすべてを削除する
    contents = contents.replace(/<[^>]*>|<\/[^>]*>/ig, "");
    
    // 通常のタグ置換後、ニコニコ動画のタグを元に戻す
    contents = contents.replace(/&lt;externalvideo src=&quot;NC:/g, "<externalvideo src='NC:");
    contents = contents.replace(/:D&quot;&gt;/, ":D'>");
    
    // 半角を置換する
    contents = contents.replace(/&nbsp;/g, " ");
    
    return contents;
}

/**
 * 選択中の記事を削除します
 * @param {int} index entryListから削除される記事のインデックス
 */
function removeEntry(index){
    if (editIndex == 0) {
        entryList.splice(editIndex, 1);
        refleshEntrylistBox();
        editIndex = -1;
        
        document.getElementById("stdout").value = ""
        document.getElementById("entry_title").value = "";
        document.getElementById("entry_stdin").value = "";
    }
    if (editIndex > 0) {
        var prevIndex = document.getElementById("logBox").selectedIndex - 1;
        entryList.splice(editIndex, 1);
        refleshEntrylistBox();
        document.getElementById("logBox").selectedIndex = prevIndex;
        editIndex = editIndex - 1;
        
        entryLoader(editIndex);
    }
    
    // プレビューエリアをクリアします
    document.getElementById("previewArea").innerHTML = "";
}

/**
 * すべての記事を削除します
 */
function allRemoveEntry(){
    entryList = [];
    
    editIndex = -1;
    refleshEntrylistBox();
    
    document.getElementById("stdout").value = ""
    document.getElementById("entry_title").value = "";
    document.getElementById("entry_stdin").value = "";
}

/**
 * 全DOMが使用可能になり次第、自動的に呼ばれる関数
 */
function initLoad(){
    if (outputValidateMode == 1) {
        document.getElementById("addContentBr").checked = true;
    }
    else {
        document.getElementById("addContentBr").checked = false;
    }
    
    logXMLLoader();
}

/**
 * ログファイル選択用のコンボボックスをid名:logSelecterに生成します
 */
function logXMLLoader(){
    // ログ用のXMLを読み込みます
    jQuery.ajax({
        url: logXmlUrl,
        method: "GET",
        success: function(xmlData){
            var separateTag = xmlData.getElementsByTagName("file");
            var fileList = new Array(separateTag.length);
            var initUrl;
            
            // 読み込んだ要素をStoreに格納して表示
            var boxBuffer = [];
            boxBuffer.push("<form name='logform'><select name='logbox' style='width: " + comboWidth + "px' onchange='xmlLoader(this.options[this.selectedIndex].value)'>");
            for (var i = 0; i < separateTag.length; i++) {
                if (i == 0) {
                    initUrl = separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue;
                }
                boxBuffer.push("<option value='" + separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue + "'/>" + separateTag[i].getElementsByTagName("display")[0].firstChild.nodeValue + " (" + separateTag[i].getElementsByTagName("path")[0].firstChild.nodeValue + ")" + "</option>");
            }
            boxBuffer.push("</select></form>");
            
            // コンボボックス要素を生成
            document.getElementById("logSelecter").innerHTML = boxBuffer.join("");
            
            // 最新の日記をローディングする
            xmlLoader(initUrl);
        },
        error: showError
    });
}

/**
 * URLを指定し、指定されたFeedXmlを読み込み、解析を行います
 * @param {String} url
 */
function xmlLoader(url){
    // 日記本体のデータをローディングする
    var loader = new jQuery.ajax({
        url: url,
        method: "GET",
        success: analyzeTargetXml,
        error: showError
    });
}

/**
 * 引数に存在するXMLデータを解析し、画面に反映します
 * @param {Object} xmlData
 */
function analyzeTargetXml(xmlData){
    var rootTag = xmlData.getElementsByTagName("feed");
    var entryTag = xmlData.getElementsByTagName("entry");
    
    // グローバル変数を初期化
    feedInfo = null;
    entryList = [];
    
    feedInfo = new FeedInfo(rootTag[0]);
    for (var i = 0; i < entryTag.length; i++) {
        entryList.push(new Entry(entryTag[i]));
    }
    
    feedinfoLoader(feedInfo);
    pageAddr = feedInfo.alternate;
    
    refleshEntrylistBox();
    document.getElementById("entry_title").value = "";
    document.getElementById("entry_stdin").value = "";
    document.getElementById("stdout").value = "";
    editIndex = -1;
    
    // プレビューエリアをクリアします
    document.getElementById("previewArea").innerHTML = "";
}

/**
 * feedInfo変数の内容をHTMLに反映します
 * @param {FeedInfo} finfo 反映するfeedInfo変数
 */
function feedinfoLoader(finfo){
    document.getElementById("feed_title").value = finfo.title;
    document.getElementById("feed_subtitle").value = finfo.subtitle;
    document.getElementById("feed_self").value = finfo.self;
    document.getElementById("feed_alternate").value = finfo.alternate;
    document.getElementById("feed_id").value = finfo.id;
    document.getElementById("feed_rights").value = finfo.rights;
    document.getElementById("feed_authorname").value = finfo.authorname;
    document.getElementById("feed_authoremail").value = finfo.authoremail;
}

/**
 * HTMLの内容をFeedInfoに変換します
 */
function applyFeedinfo(){
    var finfo = new Object();
    finfo.title = document.getElementById("feed_title").value;
    finfo.subtitle = document.getElementById("feed_subtitle").value;
    finfo.self = document.getElementById("feed_self").value;
    finfo.alternate = document.getElementById("feed_alternate").value;
    finfo.id = document.getElementById("feed_id").value;
    finfo.rights = document.getElementById("feed_rights").value;
    finfo.authorname = document.getElementById("feed_authorname").value;
    finfo.authoremail = document.getElementById("feed_authoremail").value;
    
    return finfo;
}

/**
 * 指定したEntryList上のインデックスの記事をロードします
 * @param {int} index
 */
function entryLoader(index){
    if (index < 0) {
        document.getElementById("entry_title").value = "";
        document.getElementById("entry_stdin").value = "";
        editIndex = -1;
    }
    else {
        document.getElementById("entry_title").value = entryList[index].title;
        document.getElementById("entry_stdin").value = entryList[index].content;
        editIndex = index;
    }
    
    // プレビューエリアをクリアします
    document.getElementById("previewArea").innerHTML = "";
}

/**
 * 記事一覧の情報を表示するセレクトボックスにentryListの情報を反映させます
 */
function refleshEntrylistBox(){
    var stringBuffer = [];
    stringBuffer.push("<form name='logform'><select id='logBox' style='width: " + comboWidth + "px' onchange='entryLoader(this.options[this.selectedIndex].value)'>");
    stringBuffer.push("<option value='-1'>新規作成</option>");
    for (var i = 0; i < entryList.length; i++) {
        stringBuffer.push("<option value='" + i + "'/>" + entryList[i].title + "</option>");
    }
    stringBuffer.push("</select></form>");
    // コンボボックス要素を生成
    document.getElementById("entrySelect").innerHTML = stringBuffer.join("");
}

/**
 * Feed基本情報保持クラス
 * @param {Object} obj
 */
function FeedInfo(obj){
    this.title = $("title:first", obj).text();
    this.subtitle = $("subtitle:first", obj).text();
    this.self = $("link[rel=self]", obj).attr("href");
    this.alternate = $("link[rel=alternate]", obj).attr("href");
    this.updated = $("updated:first", obj).text();
    this.id = $("id:first", obj).text();
    this.rights = $("rights:first", obj).text();
    this.authorname = $("author>name", obj).text();
    this.authoremail = $("author>email", obj).text();
}

/**
 * 記事クラス
 * @param {Object} obj entry 要素の DOM オブジェクト
 */
function Entry(obj){
    this.id = $("id:first", obj).text();
    this.title = $("title:first", obj).text();
    this.summary = $("summary:first", obj).text();
    this.published = $("published:first", obj).text();
    this.updated = $("updated:first", obj).text();
    this.link = $("link:first", obj).attr("href");
    this.content = $("content:first", obj).text();
    
    if (inputValidateMode == 1) {
        this.content = this.content.replace(/[\r\n]|\r\n/g, "");
        this.content = this.content.replace(/<br[ \/]*>/ig, "\n");
        this.content = this.content.replace(/^[ \t]*/mg, "");
    }
}

/**
 * グローバル変数からXMLを生成し、返却します
 * @param {FeedInfo} finfo
 * @param {Entry[]} elist
 */
function toXml(finfo, elist){
    var stringBuffer = [];
    
    stringBuffer.push('<?xml version="1.0" encoding="utf-8"?>');
    stringBuffer.push('<feed xml:lang="ja-jp" xmlns="http://www.w3.org/2005/Atom">');
    stringBuffer.push('');
    
    stringBuffer.push('<title type="text">' + finfo.title + '</title>');
    stringBuffer.push('<subtitle type="text">' + finfo.subtitle + '</subtitle>');
    stringBuffer.push('<link rel="self" type="application/atom+xml" href="' + finfo.self + '" />');
    stringBuffer.push('<link rel="alternate" type="text/html" href="' + finfo.alternate + '" />');
    stringBuffer.push('<updated>' + getDate() + '</updated>');
    stringBuffer.push('<id>' + finfo.id + '</id>');
    stringBuffer.push('<rights type="text">' + finfo.rights + '</rights>');
    stringBuffer.push('<author>');
    stringBuffer.push('    <name>' + finfo.authorname + '</name>');
    stringBuffer.push('    <email>' + finfo.authoremail + '</email>');
    stringBuffer.push('</author>');
    stringBuffer.push('');
    
    for (var i = 0; i < elist.length; i++) {
        var temp_content;
        if (document.getElementById("addContentBr").checked) {
            temp_content = xmlAttrContentEscape(convertContent(elist[i].content));
        }
        else {
            temp_content = xmlAttrContentEscape(elist[i].content);
        }
        
        stringBuffer.push('<entry>');
        stringBuffer.push('<id>' + elist[i].id + '</id>');
        stringBuffer.push('<title>' + elist[i].title + '</title>');
        stringBuffer.push('<summary>' + elist[i].summary + '</summary>');
        stringBuffer.push('<published>' + elist[i].published + '</published>');
        stringBuffer.push('<updated>' + elist[i].updated + '</updated>');
        stringBuffer.push('<link href="' + elist[i].link + '" />');
        stringBuffer.push('<content type="html">' + temp_content + '</content>');
        stringBuffer.push('</entry>');
        stringBuffer.push('');
    }
    
    stringBuffer.push('</feed>');
    
    return stringBuffer.join("\n");
}

/**
 * <content>要素の変換を行います
 * @param {String} content
 */
function convertContent(content){
    if (document.getElementById("addContentBr").checked) {
        content = content.replace(/[\n\r]|\r\n/g, "<br>\n");
    }
    else {
        content = content.replace(/<br>/ig, "\n");
    }
    
    return content;
}

/**
 * XMLのエスケープを行う関数
 * @param {String} str エスケープを行う文字列
 */
function xmlAttrContentEscape(str){
    return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/^[ ]+/mg, "&nbsp;").replace(/^[\t]+/mg, "");
}

/**
 * XMLの逆エスケープを行う関数
 * @param {String} str 逆エスケープを行う文字列
 */
function xmlAttrContentUnescape(str){
    return str.replace(/^[\t]+/mg, "").replace(/^[ ]+/mg, "&nbsp;").replace(/&quot;/g, '"').replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&amp;/g, "&");
}

/**
 * jQueryでのパネル開閉を制御します
 * @param {String} id 開閉するオブジェクトのid
 */
function closePanel(id){
    $("#" + id).slideToggle();
}

/**
 * エラー画面を表示します
 */
function showError(){
    alert("XMLファイルのローディング中にエラーが発生しました！");
}

/**
 * RFC3339形式の日時を出力します
 */
function getDate(){
    var dNow = new Date();
    var sYear = dNow.getFullYear();
    var sMonth = dNow.getMonth() + 1;
    var sDate = dNow.getDate();
    var sHour = dNow.getHours();
    var sMinute = dNow.getMinutes();
    var sSecond = dNow.getSeconds();
    
    // 10以下の時は頭に"0"を挿入
    if (sMonth < 10) 
        sMonth = "0" + sMonth;
    if (sDate < 10) 
        sDate = "0" + sDate;
    if (sHour < 10) 
        sHour = "0" + sHour;
    if (sMinute < 10) 
        sMinute = "0" + sMinute;
    if (sSecond < 10) 
        sSecond = "0" + sSecond;
    
    return sYear + "-" + sMonth + "-" + sDate + "T" + sHour + ":" + sMinute + ":" + sSecond + "+09:00";
}
