#!/usr/bin/ruby
# -*- coding: utf-8 -*-
# 更新履歴、および RSS を生成するスクリプト
# Satofumi KAMIMURA
#
# filename_orig.html を処理し、filename.html として出力する
#
# \todo 他のプロジェクトでも使いたくなったら、汎用化する

require 'kconv'
require "rss"


class ConfigRead
  attr_reader :replace_files, \
  :rss_base_url, :rss_title, :rss_description, :output_rss_10, :output_rss_20

  def initialize(config_file)

    @replace_files = []
    @output_rss_10 = nil
    @output_rss_20 = nil

    File.open(config_file, 'r:utf-8') { |io|
      while line = io.gets
        case line
        when /HistoryReplace\s+(.+?)\s+(.+?)\s+?([-+\d]\d*)/
          die("warning: input and output file is same.\n") if $1 == $2
          @replace_files \
          << {'original' => $1, 'output' => $2, 'number' => $3.to_i}

        when /RssBaseUrl\s+([^\s]+)/
          @rss_base_url = $1

        when /RssTitle\s+(.+$)/
          @rss_title = $1.toutf8

        when /RssDescription\s+([^\s]+)/
          @rss_description = $1.toutf8

        when /OutputRss10\s+([\w.]+)/
          @output_rss_10 = $1

        when /OutputRss20\s+([\w.]+)/
          @output_rss_20 = $1
        end
      end
    }
  end
end


# 履歴の元リソースのパース処理
def parseHistoryFile(lines)

  # 日毎のブロックの取り出し
  day_data = lines.split(/(\d\d\d\d\/\d\d\/\d\d)/)
  day_date = day_data.shift

  items = Array.new

  # 項目のブロックの取り出し
  n = day_data.size / 2
  for i in 0 ... n
    date_tag = day_data[2 * i].gsub(/\//, '-')
    date_articles = day_data[2 * i + 1]

    # 項目の登録
    date_articles.split(/\n\n/).each { |article|
      if article.sub(/---+---/, '') =~ /(.+?)\n(.+?)\n(.+)/
        items << \
        { 'link' => $1, 'title' => $2, 'date' => date_tag, 'description' => $3 }
      end
    }
  end

  items
end


# RSS ファイルの出力
def outputRssFiles(items, configs, path)

  outputs = {}
  outputs['1.0'] = configs.output_rss_10 if configs.output_rss_10
  outputs['2.0'] = configs.output_rss_20 if configs.output_rss_20

  outputs.each { |type, output|

    rss = RSS::Maker.make(type) do |maker|
      maker.channel.about = configs.rss_base_url + output
      maker.channel.title = configs.rss_title.toutf8
      maker.channel.description = configs.rss_description.toutf8
      maker.channel.link = configs.rss_base_url

      maker.items.do_sort = true

      items_num = 0;
      items.each { |article|
        maker.items.new_item do |item|
          item.link = configs.rss_base_url + article['link']
          item.title = article['title'].toutf8
          item.date = Time.parse(article['date'])
          item.description = article['description'].toutf8
        end

        items_num += 1
        if items_num >= 15
          break
        end
      }
    end
    File.open(output, 'w') { |io|
      io << rss.to_s
    }
  }
end


# 履歴文字列の置換
def outputHistoryHtml(contents_items, original, output, max_line)

  replace = ''
  pre_date = ''
  n = (max_line > 0) ? max_line : contents_items.size
  if n > contents_items.size
    n = contents_items.size
  end

  for i in 0 ... n
    item = contents_items[i]

    date = item['date']
    if date != pre_date
      replace += '  <dt>' + date + "</dt>\n"
    end
    pre_date = date;

    replace += '  <dd>' + item['description'] + "</dd>\n"
  end

  replace = "<dl>\n" + replace + "</dl>\n"

  # _CONTENTS_HISTORY_ との置換
  lines = File.read(original)
  replace_lines = lines.sub(/_CONTENTS_HISTORY_/, replace)

  # 内容の書き出し
  # !!! もっと他に書き方があるよなぁ...
  File.open(output, 'w') { |io|
    io.write(replace_lines)
  }
end


# 引数の確認
if ARGV.length < 2
  print "usage:\n\t" + __FILE__ + " history_conf.txt history_log.txt\n"
  exit(1)
end
config_file = ARGV[0]
history_file = ARGV[1]

# 設定の読み出し
configs = ConfigRead.new(config_file)


# ファイル内容を読み出し、UTF-8 に変換した上で、項目別にパースする
lines = File.read(history_file).toutf8
#lines = File.read(history_file).toeuc
contents_items = parseHistoryFile(lines)

# RSS ファイルの出力
outputRssFiles(contents_items, configs, './')

# 指定ページの _CONTENTS_HISTORY_ を指定件数の記事で置換する
configs.replace_files.each { |replace|
  outputHistoryHtml(contents_items, \
                    replace['original'], replace['output'], replace['number'])
}
