# encoding: utf-8
=begin

 * Name: SiSU

 * Description: a framework for document structuring, publishing and search

 * Author: Ralph Amissah

 * Copyright: (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
   2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Ralph Amissah,
   All Rights Reserved.

 * License: GPL 3 or later:

   SiSU, a framework for document structuring, publishing and search

   Copyright (C) Ralph Amissah

   This program is free software: you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the Free
   Software Foundation, either version 3 of the License, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
   more details.

   You should have received a copy of the GNU General Public License along with
   this program. If not, see <http://www.gnu.org/licenses/>.

   If you have Internet connection, the latest version of the GPL should be
   available at these locations:
   <http://www.fsf.org/licensing/licenses/gpl.html>
   <http://www.gnu.org/licenses/gpl.html>

   <http://www.sisudoc.org/sisu/en/manifest/gpl.fsf.html>

 * SiSU uses:
   * Standard SiSU markup syntax,
   * Standard SiSU meta-markup syntax, and the
   * Standard SiSU object citation numbering and system

 * Hompages:
   <http://www.jus.uio.no/sisu>
   <http://www.sisudoc.org>

 * Git
   <http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=summary>
   <http://git.sisudoc.org/gitweb/?p=code/sisu.git;a=blob;f=lib/sisu/v6/ao.rb;hb=HEAD>

 * Ralph Amissah
   <ralph@amissah.com>
   <ralph.amissah@gmail.com>

 ** Description: preprocessing, (document abstraction), data abstraction used
   in subsequent processing

=end
module SiSU_AO
  require_relative 'se'                                 # se.rb
    include SiSU_Env
  require_relative 'dp'                                 # dp.rb
    include SiSU_Param
  require_relative 'ao_doc_objects'                     # ao.rb
  require_relative 'ao_syntax'                          # ao_syntax.rb
    include SiSU_AO_Syntax
  require_relative 'ao_doc_str'                         # ao_doc_str.rb
  require_relative 'ao_idx'                             # ao_idx.rb
  require_relative 'ao_numbering'                       # ao_numbering.rb
  require_relative 'ao_hash_digest'                     # ao_hash_digest.rb
  require_relative 'ao_endnotes'                        # ao_endnotes.rb
  require_relative 'ao_images'                          # ao_images.rb
  require_relative 'ao_metadata'                        # ao_metadata.rb
  require_relative 'ao_character_check'                 # ao_character_check.rb
  require_relative 'ao_misc_arrange'                    # ao_misc_arrange.rb
  require_relative 'ao_expand_insertions'               # ao_expand_insertions.rb
  require_relative 'prog_text_translation'              # prog_text_translation.rb
  require_relative 'shared_sem'                         # shared_sem.rb
  class Instantiate < SiSU_Param::Parameters::Instructions
    def initialize
      @@flag_vocab=0
      @@line_mode=''
    end
  end
  class Source <Instantiate
    @@ao_array=[]
    @@idx_arr={ sst: [], tex: [], html: [], xhtml: [] }
    @@map_arr={ nametags: [], ocn_htmlseg: [] }
    @@fns=nil
    def initialize(opt,fnx=nil)
      @opt,@fnx=opt,fnx
      @@fns ||=opt.fns
      fn_use=if fnx \
      and fnx =~/\.ss[tmi]$/
        fnx
      elsif opt.fns =~/\.ssm$/
        opt.fns + '.sst'
      else
        opt.fns
      end
      @make_fns=SiSU_Env::InfoFile.new(fn_use)
      @fnm=@make_fns.marshal.ao_metadata
      @fnc=@make_fns.marshal.ao_content
      @idx_sst=@make_fns.marshal.ao_idx_sst_rel_html_seg
      @idx_raw=@make_fns.marshal.ao_idx_sst_rel
      @idx_html=@make_fns.marshal.ao_idx_html
      @idx_xhtml=@make_fns.marshal.ao_idx_xhtml
      @map_nametags=@make_fns.marshal.ao_map_nametags
      @map_ocn_htmlseg=@make_fns.marshal.ao_map_ocn_htmlseg
      @env=SiSU_Env::InfoEnv.new
    end
    def read                                                                   #creates ao
      begin
        @@ao_array=[]
        @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
        ? @fnx
        : @opt.fns
        create_ao
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@@fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
    def get                                                                    #reads ao, unless does not exist then creates first
      begin
        ao=[]
        unless @@fns==@opt.fns \
        or @@fns==@fnx
          @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
          ? @fnx
          : @opt.fns
          @@ao_array=[]
        end
        ao=(@@ao_array.empty?) \
        ? read_fnc
        : @@ao_array.dup
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
    def get_idx_sst                                                            #reads ao idx.sst, #unless does not exist then creates first
      begin
        ao=[]
        unless @@fns==@opt.fns \
        or @@fns==@fnx
          @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
          ? @fnx
          : @opt.fns
          @@idx_arr[:sst]=[]
        end
        ao=(@@idx_arr[:sst].empty?) \
        ? read_idx_sst
        : @@idx_arr[:sst].dup #check
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
    def get_idx_raw
      begin
        ao=[]
        unless @@fns==@opt.fns \
        or @@fns==@fnx
          @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
          ? @fnx
          : @opt.fns
          @@idx_arr[:tex]=[]
        end
        ao=(@@idx_arr[:tex].empty?) \
        ? read_idx_raw
        : @@idx_arr[:tex].dup #check
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
    def get_idx_html                                                           #reads ao idx.html, #unless does not exist then creates first
      begin
        ao=[]
        unless @@fns==@opt.fns \
        or @@fns==@fnx
          @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
          ? @fnx
          : @opt.fns
          @@idx_arr[:html]=[]
        end
        ao=(@@idx_arr[:html].empty?) \
        ? read_idx_html
        : @@idx_arr[:html].dup
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
    def get_idx_xhtml                                                          #reads ao idx.xhtml, #unless does not exist then creates first
      begin
        ao=[]
        unless @@fns==@opt.fns \
        or @@fns==@fnx
          @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
          ? @fnx
          : @opt.fns
          @@idx_arr[:xthml]=[]
        end
        ao=(@@idx_arr[:xhtml].empty?) \
        ? read_idx_xhtml
        : @@idx_arr[:xhtml].dup
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
    def get_map_nametags                                                       #reads ao map.nametags, #unless does not exist then creates first
      begin
        ao=[]
        unless @@fns==@opt.fns \
        or @@fns==@fnx
          @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
          ? @fnx
          : @opt.fns
          @@map_arr[:nametags]=[]
        end
        ao=(@@map_arr[:nametags].empty?) \
        ? read_map_nametags
        : @@map_arr[:nametags].dup
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
    def get_map_ocn_htmlseg                                                    #reads ao map.ocn_htmlseg, #unless does not exist then creates first
      begin
        ao=[]
        unless @@fns==@opt.fns \
        or @@fns==@fnx
          @@fns=(@fnx && @fnx =~/\.ss[tmi]$/) \
          ? @fnx
          : @opt.fns
          @@map_arr[:ocn_htmlseg]=[]
        end
        ao=(@@map_arr[:ocn_htmlseg].empty?) \
        ? read_map_ocn_htmlseg
        : @@map_arr[:ocn_htmlseg].dup
      rescue
        SiSU_Errors::Rescued.new($!,$@,@opt.selection,@opt.fns).location do
          __LINE__.to_s + ':' + __FILE__
        end
      ensure
        SiSU_AO::Instantiate.new
      end
    end
  protected
    def create_ao
      ao_array=[]
      unless @opt.act[:quiet][:set]==:on
        tell=(@opt.act[:verbose][:set]==:on \
        || @opt.act[:verbose_plus][:set]==:on \
        || @opt.act[:maintenance][:set]==:on) \
        ? SiSU_Screen::Ansi.new(
            @opt.act[:color_state][:set],
            'Document Abstraction'
          )
        : SiSU_Screen::Ansi.new(
            @opt.act[:color_state][:set],
            'Document Abstraction',"[#{@opt.f_pth[:lng_is]}] #{@opt.fno}"
          )
        tell.blue_title_hi
      end
      fn=(@fnx && @fnx =~/\.ss[tmi]$/) \
      ? @fnx
      : @opt.fns
      if @opt.fno =~/\.txz$/
        Dir.chdir(@opt.f_pth[:pth])
      end
      meta=file_array=@env.source_file_processing_array(fn)
      @md=SiSU_Param::Parameters::Instructions.new(meta,@opt).extract
      meta=nil
      ao=SiSU_AO::Make.new(fn,@md,file_array).song
      if (@opt.act[:verbose][:set]==:on \
      || @opt.act[:verbose_plus][:set]==:on \
      || @opt.act[:maintenance][:set]==:on)
        cf=SiSU_Env::CreateFile.new(fn)
        if (@opt.act[:verbose][:set]==:on \
        || @opt.act[:verbose_plus][:set]==:on)
            SiSU_Screen::Ansi.new(
            @opt.act[:color_state][:set],
            @opt.fns,
            "~meta/#{@opt.fns}.meta"
          ).output
        elsif @opt.act[:maintenance][:set]==:on
          SiSU_Screen::Ansi.new(
            @opt.act[:color_state][:set],
            "ao -> #{cf.meta}"
          ).txt_grey
        end
      end
      ao.each {|s| ao_array << s}
      if @opt.act[:maintenance][:set]==:on
        ao_array.each do |obj|
          if defined? obj.parent
            if defined? obj.ln
              if defined? obj.node
                puts %{#{obj.ln}: #{obj.ocn} : #{obj.parent} : #{obj.node} - #{obj.lc}}
              else
                puts %{#{obj.ln}: #{obj.ocn} : #{obj.parent}}
              end
            else
              if defined? obj.node
                puts %{   #{obj.ocn} : #{obj.parent} : #{obj.node} - #{obj.lc}}
              else
                puts %{   #{obj.ocn} : #{obj.parent}}
              end
            end
          end
        end
      end
      ao_array
    end
    def read_fnm
      ao=[]
      ao=(FileTest.file?(@fnm)) \
      ? (File.open(@fnm,'r:utf-8'){ |f| ao=Marshal.load(f)})
      : SiSU_AO::Source.new(@opt).create_ao
    end
    def read_fnc
      ao=[]
      ao=(FileTest.file?(@fnc)) \
      ? (File.open(@fnc,'r:utf-8'){ |f| ao=Marshal.load(f)})
      : SiSU_AO::Source.new(@opt).create_ao
    end
    def read_idx_sst
      m=[]
      m=(FileTest.file?(@idx_sst)) \
      ? (File.open(@idx_sst,'r:utf-8'){ |f| m=Marshal.load(f)})
      : nil
    end
    def read_idx_raw
      m=[]
      m=(FileTest.file?(@idx_raw)) \
      ? (File.open(@idx_raw,'r:utf-8'){ |f| m=Marshal.load(f)})
      : nil
    end
    def read_idx_html
      m=[]
      m=(FileTest.file?(@idx_html)) \
      ? (File.open(@idx_html,'r:utf-8'){ |f| m=Marshal.load(f)})
      : nil
    end
    def read_idx_xhtml
      m=[]
      m=(FileTest.file?(@idx_xhtml)) \
      ? (File.open(@idx_xhtml,'r:utf-8'){ |f| m=Marshal.load(f)})
      : nil
    end
    def read_map_nametags
      m=[]
      m=(FileTest.file?(@map_nametags)) \
      ? (File.open(@map_nametags,'r:utf-8'){ |f| m=Marshal.load(f)})
      : nil
    end
    def read_map_ocn_htmlseg
      m=[]
      m=(FileTest.file?(@map_ocn_htmlseg)) \
      ? (File.open(@map_ocn_htmlseg,'r:utf-8'){ |f| m=Marshal.load(f)})
      : nil
    end
  end
  class Output
    def initialize(fn,md,data)
      @fn,@md,@data=fn,md,data
      @cf=SiSU_Env::CreateFile.new(@fn)
      @make=SiSU_Env::InfoFile.new(@fn)
      @dir=SiSU_Env::InfoEnv.new(@fn)
    end
    def screen_dump(o)
      if defined? o.of
        print %{OF: #{o.of}; }
      end
      if defined? o.is
        print %{IS: #{o.is.to_s}; }
      end
      if defined? o.ocn
        print %{OCN: #{o.ocn}; }
      end
      if defined? o.node
        print %{NODE: #{o.node}; }
      end
      if defined? o.parent
        print %{Parent: #{o.parent}; }
      end
      if defined? o.obj and not o.obj.empty?
        puts %{\n#{o.obj}; }
      else "\n"
      end
    end
    def screen_print(t_o)
      if defined? t_o
        print ' ' + t_o.to_s
      end
    end
    def screen_output(data)
      data.each do |o|
        print o.class
        screen_print(o.ocn)
        screen_print(o.obj)
        puts "\n"
      end
    end
    def hard_output
      if @md.opt.act[:maintenance][:set]==:on
        filename_meta=@cf.metaverse.file_meta
        @data.each {|o| filename_meta.puts o.inspect.sub(/:0x[0-9a-f]{8}\s/,': ')} #to make diffing easier
        filename_txt=@cf.metaverse.file_txt
        @data.each do |o|
          if defined? o.ocn
            filename_txt.puts case o.is
            when :heading
              "[#{o.is.to_s} #{o.lv}~#{o.name} [#{o.ocn}]] #{o.obj}"
            else "[#{o.is.to_s} [#{o.ocn}]] #{o.obj}"
            end
          else
            filename_txt.puts case o.is
            when :meta
              "[m~#{o.tag}] #{o.obj}"
            else "[#{o.is.to_s}] #{o.obj}"
            end
          end
        end
        filename_debug=@cf.file_debug
        @data.each do |o|
          if defined? o.ocn
            case o.is
            when :heading
              filename_debug.puts
                "#{o.is.to_s} #{o.lv}~#{o.name} odv=#{o.odv} osp=#{o.osp} [#{o.ocn}] -->\n\t#{o.obj}"
            end
          end
        end
      else
        hard="#{@dir.processing_path.ao}/#{@md.fns}.meta"
        File.unlink(hard) if FileTest.file?(hard)
        hard="#{@dir.processing_path.ao}/#{@md.fns}.txt"
        File.unlink(hard) if FileTest.file?(hard)
        hard="#{@dir.processing_path.ao}/#{@md.fns}.debug.txt"
        File.unlink(hard) if FileTest.file?(hard)
      end
    end
    def make_marshal_content
      marshal_ao=@make.marshal.ao_content
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} if @data.is_a?(Array)
    end
    def make_marshal_metadata
      marshal_ao=@make.marshal.ao_metadata
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} if @data.is_a?(Array)
    end
    def idx_html_hard_output
      if @md.book_idx \
      and @md.opt.act[:maintenance][:set]==:on
        filename_meta=@cf.file_meta_idx_html
        if @data.is_a?(Array)
          @data.each {|s| p s.inspect + "\n" unless s.is_a?(String)}
          @data.each {|s| filename_meta.puts s.strip + "\n" unless s.strip.empty?}
        end
      else
        hard_idx_html="#{@dir.processing_path.ao}/#{@md.fns}.idx.html"
        File.unlink(hard_idx_html) if FileTest.file?(hard_idx_html)
      end
    end
    def make_marshal_idx_sst_html_seg
      marshal_ao=@make.marshal.ao_idx_sst_rel_html_seg
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
        if @data.is_a?(Array)
    end
    def make_marshal_idx_sst_rel
      marshal_ao=@make.marshal.ao_idx_sst_rel
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
        if @data.is_a?(Array)
    end
    def make_marshal_idx_html
      marshal_ao=@make.marshal.ao_idx_html
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
        if @data.is_a?(Array)
    end
    def make_marshal_idx_xhtml
      marshal_ao=@make.marshal.ao_idx_xhtml
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
        if @data.is_a?(Array)
    end
    def make_marshal_map_nametags
      marshal_ao=@make.marshal.ao_map_nametags
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
        if @data.is_a?(Hash)
    end
    def make_marshal_map_name_ocn_htmlseg
      marshal_ao=@make.marshal.ao_map_ocn_htmlseg
      File.open(marshal_ao,'w'){|f| Marshal.dump(@data,f)} \
        if @data.is_a?(Hash)
    end
  end
  class Make
    def initialize(fn,md,data)
      @fn,@md,@data=fn,md,data
      @env=SiSU_Env::InfoEnv.new(@md.fns)
    end
    def reset
      @@flag_vocab=0
      @@line_mode=''
    end
    def song
      reset
      data_txt=@data
      data_txt=
        SiSU_AO_Insertions::Insertions.new(@md,data_txt).            # ao_expand_insertions.rb
          expand_insertions?
      data_txt=
        SiSU_AO_MiscArrangeText::SI.new(@md,data_txt).               # ao_misc_arrange.rb
          prepare_text
      data_obj,
        metadata=
          SiSU_AO_DocumentStructureExtract::Build.new(@md,data_txt). # ao_doc_str.rb
            identify_parts
      data_obj=
        SiSU_AO_Syntax::Markup.new(@md,data_obj).songsheet           # ao_syntax.rb
      data_obj,
        endnote_array=
          SiSU_AO_CharacterCheck::Check.new(data_obj).               # ao_character_check.rb
            character_check_and_oldstyle_endnote_array
      data_obj=
         SiSU_AO_Images::Images.new(@md,data_obj).images             # ao_images.rb
      data_obj,
        tags_map,
        ocn_html_seg_map=
          SiSU_AO_Numbering::Numbering.new(@md,data_obj).            # ao_numbering.rb
            numbering_song
      data_obj,
        book_index_rel,
        book_index_rel_html_seg,
        html_idx,xhtml_idx=
          SiSU_AO_BookIndex::BookIndex.new(@md,data_obj,@env).       # ao_idx.rb
            indexing_song if @md.book_idx
      data_obj=
        SiSU_AO_Endnotes::Endnotes.new(@md,data_obj,endnote_array).  # ao_endnotes.rb
          endnotes
      outputdata=data_obj
      if (@md.opt.act[:ao][:set]==:on \
      || @md.opt.act[:maintenance][:set]==:on)
        SiSU_AO::Output.new(@fn,@md,outputdata).hard_output
        SiSU_AO::Output.new(@fn,@md,outputdata).make_marshal_content
        SiSU_AO::Output.new(@fn,@md,metadata).make_marshal_metadata
        SiSU_AO::Output.new(@fn,@md,html_idx).idx_html_hard_output
        SiSU_AO::Output.new(@fn,@md,book_index_rel_html_seg).make_marshal_idx_sst_html_seg
        SiSU_AO::Output.new(@fn,@md,book_index_rel).make_marshal_idx_sst_rel
        SiSU_AO::Output.new(@fn,@md,html_idx).make_marshal_idx_html
        SiSU_AO::Output.new(@fn,@md,xhtml_idx).make_marshal_idx_xhtml
        SiSU_AO::Output.new(@fn,@md,tags_map).make_marshal_map_nametags
        SiSU_AO::Output.new(@fn,@md,ocn_html_seg_map).make_marshal_map_name_ocn_htmlseg
      end
      reset
      outputdata
    end
  protected
  end
end
__END__
