# -*- encoding: utf-8 -*-

require 'pathname'
require 'set'
require 'yaml'
require 'webgen/path_handler/base'
require 'webgen/path_handler/page_utils'
require 'webgen/utils'

module Webgen
  class PathHandler

    # Handles meta information paths which provide meta information for other paths.
    class MetaInfo

      include Base
      include PageUtils

      # Upon creation the path handler registers itself as listener for the :apply_meta_info_to_path and
      # :after_node_created hooks so that it can apply the meta information.
      def initialize(website)
        super
        @website.blackboard.add_listener(:apply_meta_info_to_path, 'path_handler.meta_info',
                                         &method(:apply_meta_info_to_path))
        @website.blackboard.add_listener(:after_node_created, 'path_handler.meta_info',
                                         :before => 'item_tracker.node_meta_info', &method(:after_node_created))
        @paths = []
        @alcns = []
      end

      # Create a meta info node from +path+.
      def create_nodes(path, blocks)
        @paths += add_data(path, blocks['paths'], 'paths')
        entries = add_data(path, blocks['alcn'], 'alcn')
        @alcns += entries
        update_existing_nodes(entries)

        nil
      end

      #######
      private
      #######

      # Add the data from the given page block to the hash.
      def add_data(path, content, block_name)
        entries = []
        if content && (data = Utils.yaml_load(content))
          data.each do |(*keys), value|
            value = Marshal.dump(value)
            keys.each {|key| entries << [Webgen::Path.append(path.parent_path, key), value]}
          end
        end
        entries
      rescue Exception => e
        raise Webgen::NodeCreationError.new("Could not parse block '#{block_name}': #{e.message}", "path_handler.meta_info")
      end

      # Update already existing nodes with meta information from the given meta info node.
      def update_existing_nodes(entries)
        @website.tree.node_access[:alcn].each do |alcn, node|
          entries.each do |pattern, mi|
            node.meta_info.update(Marshal.load(mi)) if Webgen::Path.matches_pattern?(alcn, pattern)
          end
        end
      end

      # Update the meta info of matched path before a node is created.
      def apply_meta_info_to_path(path)
        hash = {}
        @paths.each do |pattern, mi|
          hash.merge!(Marshal.load(mi)) if Webgen::Path.matches_pattern?(path, pattern)
        end
        path.meta_info.replace(hash.merge!(path.meta_info)) if hash.length > 0
      end

      # Update the meta information of a matched alcn after the node has been created.
      def after_node_created(node)
        @alcns.each do |pattern, mi|
          node.meta_info.update(Marshal.load(mi)) if Webgen::Path.matches_pattern?(node.alcn, pattern)
        end
      end

    end

  end
end
