# 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 Lic/home/ralph/live-manual/build/manual/manifest/live-manual.ca.htmlense 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/v5/dp_make.rb;hb=HEAD>

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

 ** Description: document parameters make extracted for program use

=end

module SiSU_Param_Make
  class MdMake
    def initialize(str,opt,env)
      @s,@opt,@env=str,opt,env
    end
    def validate_length(s,l,n)
      #s=(s.length <= l) ? s : nil
      s=if s.is_a?(String) \
      and s.length <= l
        s
      elsif s.is_a?(NilClass)
        nil
      elsif s.class !=String
        STDERR.puts "#{n} is #{s.class}: programming error, String expected #{__FILE__}:#{__LINE__}"
        s
      else
        SiSU_Screen::Ansi.new(
          'v',
          "*WARN* #{n} length #{s.length} exceeds set db field length #{l}, metadata dropped",
          @opt.fns
        ).warn unless @opt.act[:quiet][:set]==:on
        nil
      end
    end
    def name_format(name)
      if name
        name=name.strip
        @name_a_h=[]
        authors=name.scan(/[^;]+/)
        authors.each_with_index do |a,i|
          b=((a =~/\s*\|\s*/) ? (a.split(/\|/)) : [a])
          if b[0] =~/"(.+?)"/
            @name_a_h << { the: $1 }
          else
            x=b[0].scan(/[^,]+/)
            if x.length==1
              @name_a_h << { the: x[0].strip }
            elsif x.length==2
              @name_a_h << { the: x[0].strip, others: x[1].strip }
            else #p x.length
            end
          end
          b.delete_at(0)
          b.each do |d|
            k,c=nil
            k,c=/^(\S+)\s+(.*)/.match(d)[1,2] if d
            @name_a_h[i][:hon]=c.strip if k=='hon'
            @name_a_h[i][:affiliation]=c.strip if k=='affiliation'
            @name_a_h[i][:nationality]=c.strip if k=='nationality'
          end
        end
        l=@name_a_h.length
        name_str=''
        @name_a_h.each_with_index do |a,i|
          name_str += if a[:others]
            z=(((l - i) > 1) ? ', ' : '')
            "#{a[:others].strip} #{a[:the].strip}" + z
          else
            z=(((l - i) > 2) ? ', ' : '')
            "#{a[:the].strip}" + z
          end
        end
        { name_a_h: @name_a_h, name_str: name_str }
      else nil
      end
    end
    def build_hash(arr)
      @h={}
      arr.each_with_index do |x,i|
        a,b=nil,nil
        if x =~/^%[:\s]/ #ignore comment
        elsif x =~/:(\S+?):\s+(.+)/
          a,b=/:(\S+?):\s+(.+)\Z/m.match(x)[1,2]
        elsif i == 0
          a='main'
          b=x
        else
        end
        @h[a]=b
      end
      @h
    end
    def make
      a=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
      @h=build_hash(a)
      def headings
        lv=[]
        x=@h['headings']
        x=((x =~/;/) ? (x.split(/;\s*/)) : [ x ])
        lv[0]=x
        lv0 ||='A~ '             #root level, single document apex, document title
        lv1=x[0] ||='B~ '
        lv[1]=/^#{lv1}/
        lv2=x[1] ||='C~ '
        lv[2]=/^#{lv2}/
        lv3=x[2] ||='D~ '
        lv[3]=/^#{lv3}/
        lv4=x[3] ||='1~ '
        lv[4]=/^#{lv4}/
        lv5=x[4] ||='2~ '
        lv[5]=/^#{lv5}/
        lv6=x[5] ||='3~ '
        lv[6]=/^#{lv6}/
        lv
      end
      def num_top
        @h['num_top']
      end
      def breaks
        pagebreaks=((@h['breaks'] =~/;/) \
        ? (@h['breaks'].split(/;\s*/))
        : [ @h['breaks'] ])
        page_new,page_break,page_line=nil,nil,nil
        pagebreaks.each do |x|
          page_new=x[/(:?[\dA-C],?)+/] if x=~/new|clear/
          page_break=x[/(:?[\dA-C],?)+/] if x =~/break/
          page_line=x[/(:?[\dA-C],?)+/] if x =~/line/
        end
        { page_new: page_new, page_break: page_break, page_line: page_line }
      end
      def language
        if @h['language'] && (@h['language']=~/\S{2,}/)
          ((@h['language'] =~/,/) \
          ? (@h['language'].split(/,\s*/))
          : [ @h['language'] ])
        else [ 'en' ]
        end
      end
      def bold
        m=@h['bold']
        i=(m=~/\/i$/)? 'i' : ''
        if m
          x=m.gsub(/^\/(.+?)\/i?/,'\1').
            gsub(/\((?:\?:)?/,'(?:')                                         # avoid need to escape use of brackets within regex provided
          rgx='\b(' + x + ')\b'
          y=((i =~/i/) ? (/#{rgx}/i) : (/#{rgx}/))
          { str: '\b(?:' + x + ')\b', regx: y, i: i }
        else nil
        end
      end
      def italics
        m=@h['italics']
        i=((m=~/\/i$/) ? 'i' : '')
        if m
          x=m.gsub(/^\/(.+?)\/i?/,'\1').
            gsub(/\((?:\?:)?/,'(?:')                                         # avoid need to escape use of brackets within regex provided
          rgx='\b(' + x + ')\b'
          y=((i =~/i/) ? (/#{rgx}/i) : (/#{rgx}/))
          { str: '\b(?:' + x + ')\b', regx: y, i: i }
        else nil
        end
      end
      def emphasis
        if @h['emphasis'] =~/bold/                   then 'bold'
        elsif @h['emphasis'] =~/italics?/            then 'italics'
        elsif @h['emphasis'] =~/under(?:line|score)/ then 'underscore'
        else nil
        end
      end
      def substitute
        m=@h['substitute']
        if m
          w=m.scan(/\/(.+?)\/(i?,)\s*'(.+?)'(?:\s+|\s*;\s*|$)/)
          arr_hash=[]
          matches=''
          w.each do |x|
            c=(x[1] =~/[i],/) ? :i : :s
            matches=matches + x[0].gsub(/([${}])/,'\\\\\1') + '|'
            arr_hash << {
              match: x[0].gsub(/([${}])/,'\\\\\1'),
              replace: x[2],
              case_s: c
            }
          end
          matches.chop!
          { match_and_replace: arr_hash, matches: matches }
        else nil
        end
      end
      def plaintext_wrap
        if @h['plaintext_wrap'].to_s =~/\d\d+/ \
        and @h['plaintext_wrap'].to_i > 19 \
        and @h['plaintext_wrap'].to_i < 201
          @h['plaintext_wrap'].to_i
        else nil
        end
      end
      def omit
        m=@h['omit']
        @m=m ? (m.split(/,\s+/)) : nil
        def list
          @m
        end
        self
      end
      def ocn?
        (omit.list.inspect =~/"ocn"/) \
        ? :off
        : :na
      end
      def toc?
        (omit.list.inspect =~/"toc"/) \
        ? :off
        : :na
      end
      def manifest?
        (omit.list.inspect =~/"manifest"/) \
        ? :off
        : :na
      end
      def links_to_manifest?
        (omit.list.inspect =~/"manifest_links"|"links_to_manifest"/) \
        ? :off
        : :na
      end
      def metadata?
        (omit.list.inspect =~/"metadata"/) \
        ? :off
        : :na
      end
      def minitoc?
        (omit.list.inspect =~/"minitoc"/) \
        ? :off
        : :na
      end
      def html_minitoc?
        (omit.list.inspect =~/"html_minitoc"/) \
        ? :off
        : :na
      end
      def html_top_band?
        (omit.list.inspect =~/"html_top_band"/) \
        ? :off
        : :na
      end
      def html_navigation?
        (omit.list.inspect =~/"html_navigation"/) \
        ? :off
        : :na
      end
      def html_navigation_bar?
        (omit.list.inspect =~/"html_navigation_bar"/) \
        ? :off
        : :na
      end
      def segsubtoc?
        (omit.list.inspect =~/"segsubtoc"/) \
        ? :off
        : :na
      end
      def search_form?
        (omit.list.inspect =~/"search_form"/) \
        ? :off
        : :na
      end
      def html_search_form?
        (omit.list.inspect =~/"html_search_form"/) \
        ? :off
        : :na
      end
      def html_right_pane?
        (omit.list.inspect =~/"html_right_column"|"html_right_pane"/) \
        ? :off
        : :na
      end
      def manifest_minitoc?
        (omit.list.inspect =~/"manifest_minitoc"/) \
        ? :off
        : :na
      end
      def cover_image?
        (omit.list.inspect =~/"cover_image"/) \
        ? :off
        : :na
      end
      def home_button_image?
        (omit.list.inspect =~/"home_button_image"/) \
        ? :off
        : :na
      end
      def texpdf_font
        def main
          @h['texpdf_font'] \
          && (@h['texpdf_font']=~/\S{3,}/) \
          ? @h['texpdf_font']
          : @env.font.texpdf.main
        end
        def sans                                                             # not used
          @h['texpdf_font_sans'] \
          && (@h['texpdf_font_sans']=~/\S{3,}/) \
          ? @h['texpdf_font_sans']
          : @env.font.texpdf.sans
        end
        def serif                                                            # not used
          @h['texpdf_font_serif'] \
          && (@h['texpdf_font_serif']=~/\S{3,}/) \
          ? @h['texpdf_font_serif']
          : @env.font.texpdf.serif
        end
        def mono
          @h['texpdf_font_mono'] \
          && (@h['texpdf_font_mono']=~/\S{3,}/) \
          ? @h['texpdf_font_mono']
          : @env.font.texpdf.mono
        end
        def cjk
          @h['texpdf_font_cjk'] \
          && (@h['texpdf_font_cjk']=~/\S{3,}/) \
          ? @h['texpdf_font_cjk']
          : @env.font.texpdf.cjk
        end
        def cjk_zh
          @h['texpdf_font_cjk_zh'] \
          && (@h['texpdf_font_cjk_zh']=~/\S{3,}/) \
          ? @h['texpdf_font_cjk_zh']
          : @env.font.texpdf.cjk_zh
        end
        def cjk_ja
          @h['texpdf_font_cjk_ja'] \
          && (@h['texpdf_font_cjk_ja']=~/\S{3,}/) \
          ? @h['texpdf_font_cjk_ja']
          : @env.font.texpdf.cjk_ja
        end
        def cjk_ko
          @h['texpdf_font_cjk_ko'] \
          && (@h['texpdf_font_cjk_ko']=~/\S{3,}/) \
          ? @h['texpdf_font_cjk_ko']
          : @env.font.texpdf.cjk_ko
        end
        self
      end
      def promo
        @h['promo']
      end
      def ad
        @h['ad']
      end
      def manpage
        manpage={}
        if @h['manpage']
          if @h['manpage'] =~/;/m
            man=@h['manpage'].split(/;/m)
            man.each do |x|
              m=(x=~/=/m) ? x.split(/=/m) : nil
              if m
                manpage[m[0].strip] = m[1].split(/ \. /)
              end
            end
          end
        end
        if manpage['name']
          manpage['name']=manpage['name'].join("\n.br\n").
            gsub(/(-)/m,"\\\\\\1").
            gsub(/\A/,"\n.br\n.SH NAME\n.br\n")
        else
          manpage['name']='man page "name/whatis" information not provided, set in header @man: name=[whatis information]'
        end
        if manpage['synopsis']
          manpage['synopsis']=manpage['synopsis'].join("\n\n.br\n").
            gsub(/(-)/m,"\\\\\\1").
            gsub(/\A/,"\n.br\n.SH SYNOPSIS\n.br\n")
        else
          manpage['synopsis']=''
        end
        unless manpage['section']
          manpage['section']=1
        end
        manpage
      end
      def get_image_dimensions(img)
        imgk=SiSU_Env::SystemCall.new.imagemagick
        gmgk=SiSU_Env::SystemCall.new.graphicksmagick
        img_pth={
          sst: @env.path.image_source_include,
          pod: File.expand_path("../../../sisupod/image" )
        }
        path_img=if FileTest.file?("#{img_pth[:pod]}/#{img}")
          "#{img_pth[:pod]}/#{img}"
        elsif FileTest.file?("#{img_pth[:sst]}/#{img}")
          "#{img_pth[:sst]}/#{img}"
        else nil
        end
        if path_img
          if imgk or gmgk
            if imgk
              imgsys=`identify #{path_img}`.strip                           #system call
            elsif gmgk
              imgsys=`gm identify #{path_img}`.strip                        #system call
            end
            w,h=/(\d+)x(\d+)/m.match(imgsys)[1,2]
          else
            w,h='600','800'
          end
        else
          w,h=nil,nil
        end
        {w: w, h: h}
      end
      def home_button_text
        if @h['home_button_text']
          @h['home_button_text'].split(/\s*;\s*/)
        else nil
        end
      end
      def home_button_image
        s=nil
        s=if @h['home_button_image']
          s=@h['home_button_image'].split(/\s*;\s*/)
          s0=s[0] #if
          image={}
          s=if s0 =~/{(\S+\.(?:jpg|png|gif))(?:\s+(\d+x\d+))?\s*}(?:(http:\/\/\S+)|image)/
            image[:home_button]=$1
            if $2
              image[:dimensions]=$2
              image[:w],image[:h]=/(\d+)x(\d+)/m.match(image[:dimensions])[1,2]
            else
              d=get_image_dimensions(image[:home_button])
              image[:w],image[:h]=d[:w],d[:h]
              image[:dimensions]="#{d[:w]}x#{d[:h]}"
            end
            image[:link]=$3
            image
          end
        else nil
        end
      end
      def cover_image
        s=nil
        if @h['cover_image']
          s=@h['cover_image'].split(/\s*;\s*/)
          s=s[0] #if
          image={}
          if s =~/{\s*(\S+\.(?:jpg|png|gif))(?:\s+(\d+x\d+))?(?:\s+"(.+?)")?\s*}image/
            image[:cover]=$1
            if $2
              image[:dimensions]=$2
              image[:w],image[:h]=/(\d+)x(\d+)/m.match(image[:dimensions])[1,2]
            else
              d=get_image_dimensions(image[:cover])
              image[:w],image[:h]=d[:w],d[:h]
              image[:dimensions]="#{d[:w]}x#{d[:h]}"
            end
            image[:note]=$3
          elsif s =~/(\S+\.(?:jpg|png|gif))/
            image[:cover]=$1
            d=get_image_dimensions(image[:cover])
            image[:w],image[:h]=d[:w],d[:h]
            image[:dimensions]="#{d[:w]}x#{d[:h]}"
            image[:note]=nil
          end
          image
        else nil
        end
      end
      def footer
        if @h['footer']
          @h['footer'].split(/\s*;\s*/)
        else nil
        end
      end
      self
    end
    def make_links
      @doc_links=@s.split(/\n%\s.+?$|[ ]*\n[ ]*/m)
      def links
        lnks,a_idx=[],0
        @doc_links.each do |doc_link|
          if doc_link=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
            say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(doc_link)[1,2]
            lnks[a_idx]={ say: say, url: url  }
            a_idx +=1
          end
        end
        lnks
      end
      def append?
        (@doc_links[0]=='+') \
          ? :yes
          : :no
      end
      self
    end
  end
  class MakeHead
    attr_accessor :pagenew,:pagebreak,:pageline,:toc,:lv1,:lv2,:lv3,:lv4,:lv5,:lv6,:num_top,:i18n,:man_section,:substitution_match_list,:bold_match_list,:italics_match_list,:emphasis_set_to,:footer_links,:home_button_links,:home_button_image,:cover_image
    def initialize(make)
      @make=make
    end
    def clear
      @pagenew=@pagebreak=@pageline=@toc=@lv1=@lv2=@lv3=@lv4=@lv5=@lv6=@num_top=@i18n=@man_section=@footer_links=@substitution_match_list=@bold_match_list=@italics_match_list=@emphasis_set_to=@home_button_links=@home_button_image=@cover_image=nil
    end
    def make_instruct
      clear
      if defined? @make.breaks \
      and @make.breaks[:page_new]                  #clearpage
        @pagenew=@make.breaks[:page_new]
      end
      if defined? @make.breaks \
      and @make.breaks[:page_break]                #newpage
        @pagebreak=@make.breaks[:page_break]
      end
      if defined? @make.breaks \
      and @make.breaks[:page_line]                 #page line across
        @pagebreak=@make.breaks[:page_line]
      end
      if defined? @make.headings \
      and @make.headings
        @toc=@make.headings[0]
        @lv1=@make.headings[1]
        @lv2=@make.headings[2]
        @lv3=@make.headings[3]
        @lv4=@make.headings[4]
        @lv5=@make.headings[5]
        @lv6=@make.headings[6]
      end
      if defined? @make.num_top \
      and @make.num_top
        @num_top=@make.num_top # remove @num_top
      end
      if defined? @make.language \
      and @make.language[0]
        @i18n=@make.language
      end
      if defined? @make.manpage \
      and @make.manpage
        @man_section=(defined? @make.manpage.section) \
        ? @make.manpage.section
        : 1
      end
      if defined? @make.substitute \
      and @make.substitute
        @substitution_match_list=@make.substitute
      end
      if defined? @make.bold \
      and @make.bold
        @bold_match_list=@make.bold
      end
      if defined? @make.italics \
      and @make.italics
        @italics_match_list=@make.italics
      end
      if defined? @make.emphasis \
      and @make.emphasis
        @emphasis_set_to=@make.emphasis
      end
      if defined? @make.footer \
      and @make.footer.is_a?(Array)
        @footer_links= { left: { say: '', url: '' }, center: { say: '', url: '' } } #already set
        @footer_links[:left]=if @make.footer[0]=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
          say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(@make.footer[0])[1,2]
          { say: say, url: url }
        else
          { say: '', url: '' }
        end
        @footer_links[:center]=if @make.footer[1]=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
          say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(@make.footer[1])[1,2]
          { say: say, url: url }
        else
          { say: '', url: '' }
        end
        @footer_links
      else #already set
        @footer_links= { left: { say: '', url: '' }, center: { say: '', url: '' } }
      end
      if defined? @make.home_button_text \
      and @make.home_button_text.is_a?(Array)
        a_idx=0
        @home_button_links=[]
        @make.home_button_text.each do |doc_link|
          if doc_link=~/\{.+?\}(?:(?:https?|file|ftp):\/|\.\.)\/\S+(?:\s|$)/
            say,url=/\{\s*(.+?)\s*\}((?:(?:https?|file|ftp):\/|\.\.)\/\S+)/im.match(doc_link)[1,2]
            @home_button_links[a_idx]= { say: say, url: url }
            a_idx +=1
          end
        end
        @home_button_links
      end
      if defined? @make.home_button_image \
      and @make.home_button_image.is_a?(Hash)
        @home_button_image=@make.home_button_image
      end
      if defined? @make.cover_image \
      and @make.cover_image.is_a?(Hash)
        @cover_image=@make.cover_image
      end
      { pagenew: @pagenew,
        pagebreak: @pagebreak,
        pageline: @pageline,
        toc: @toc,
        lv1: @lv1,
        lv2: @lv2,
        lv3: @lv3,
        lv4: @lv4,
        lv5: @lv5,
        lv6: @lv6,
        num_top: @num_top,
        i18n: @i18n,
        emphasis_set_to: @emphasis_set_to,
        bold_match_list: @bold_match_list,
        italics_match_list: @italics_match_list,
        substitution_match_list: @substitution_match_list,
        man_section: @man_section,
        footer_links: @footer_links,
        home_button_links: @home_button_links,
        home_button_image: @home_button_image,
        cover_image: @cover_image,
      }
    end
  end
end
__END__
