#-- qar_post.pm ------------------------------------------------------------
#
# (c) Copyright Programming Research 2011
#
# Written: C. Waddingham, 11-11-2011
#
# Purpose: Provides post processor to XSLT stage.
#
# DIVIDE_REPORT chops up the monolithic report (e.g. "Quality Report.xhtml")
# into sections, and structures the report for a browser display with index
# on the lhs, and the report sections rendered on the rhs.
# DIVIDE_REPORT relies on intrinsic structure of the xml report being in
# prdf sections optionally with dividers.  It reads the output of the XSLT
# phase and performs manipulation of the xhtml|html in the report.xhtml,
# or report.html file, using simple Perl processing only.
# This entire 3rd phase of processing is performed in QAR_POST.
# Can only do this for xhtml and html reports, and not pdf etc.
#
#---------------------------------------------------------------------------

#-- package QAR_POST: ------------------------------------------------------

package QAR_POST;

use strict;

require QAR_OPT;
require QAR_UTIL;

#------------------------------------------------------------------------

sub DIVIDE_REPORT
{
  # Usage: $phase_three_result_file = DIVIDE_REPORT( $phase_two_result_file );
  #
  my $phase_two_result_file = shift;

  my $output_path   = QAR_UTIL::APPLY_FINAL_SEP( QAR_OPT::OUTPUT_PATH() );
  my $report_format = QAR_OPT::REPORT_FORMAT();
  my $report_type   = QAR_OPT::REPORT_TYPE();

  #------------------------------------------------------------------------
  #
  # Read the existing phase two result file.
  # Get preamble (ie file upto end of Contents),
  # And major sections of the report.
  #

  my $phase_three_result_file = 
    $output_path .
    $report_type . "-Main." . 
    $report_format;

  my $REP = OPEN( "<$phase_two_result_file" );

  my $preamble = "";
  my $line;
  my $prev_line = "";

  # Also get html <title> element
  #
  my $title = "";
    
  PREAMBLE:
  while ( $line = <$REP> )
  {
    if ( $line =~ /^<title>(.*?)<\/title>/oi )
    {
      $title = $1;
    }
    elsif ( $line =~ /^<h.>$/oi )
    {
      $prev_line = $line;
      $line = <$REP>;
  
      last PREAMBLE if ( $line =~ /^<a name=/o );
    }
  
    $preamble .= $line;
  }
  
  # Current $line is first line of first section.
  #
  my $line_p1 = $line;
  
  #------------------------------------------------------------------------
  #
  # Get preamble less the 'Contents' section for the first section.
  #
  my $section_one_header = "";
  
  SECTION_ONE_HEADER:
  for my $line ( split( "\n", $preamble ) )
  {
    last SECTION_ONE_HEADER if ( $line =~ /^<h.>Contents<\/h.>\s*$/oi );
  
    $section_one_header .= $line . "\n";
  }
  
  #------------------------------------------------------------------------
  #
  # Get common header information from preamble.
  # ie Get preamble upto and including </head> but no more
  #
  my $header = "";
  
  HEADER:
  for my $line ( split( "\n", $preamble ) )
  {
    $header .= $line . "\n";
    last HEADER if ( $line =~ /<\/head>$/o );
  }
  
  $header .= "<body>\n<div>\n";

  my $postlude = "</div>\n</body>\n</html>\n";
  
  #------------------------------------------------------------------------
  #
  # Read the remainder of the phase two result file and write into separate files
  # for each divide division.
  #  

  ( my $section_one_name = $line_p1 ) =~ s/^.*\"(.*?)\".*[\n\r]*$/$1/o;
  my $section_name = $section_one_name;

  my $line_p2 = <$REP>;
  my $section_title = $prev_line . $line_p1 . $line_p2;

  my $section_preamble = $section_one_header;

  my $division_name = "";
  my $division_open = 0;  # false
  my $first_section = 1;  # true
  my $ar_section_names = [];
  my $ar_current_section_division_names = [];
  my $DIVISION;
  my $ar_SECTION_STACK = [];
  ( my $title_level = $prev_line ) =~ s/^<h(.)>[\n\r]*$/$1/oi;

  push @$ar_SECTION_STACK,
    { TITLE => $title_level,
      NAME  => "$output_path$report_type-$section_name.$report_format",
      HEAD  => $section_preamble . $section_title,
      BODY  => ""
    };

  WRITE_DIVISIONS:
  while ( $line = <$REP> )
  {
    if ( $line =~ /^<h(.)>$/oi )
    {
      # Here with potential section header.
      # Look for bookmark anchor <a name
      #
      $title_level = $1;
      $line_p1 = <$REP>;
      $line_p2 = <$REP>;

      $section_title = $line . $line_p1 . $line_p2;

      $section_preamble = $header;

      if ( $line_p1 =~ /^<a name=/oi )
      {
        # Close any previous division
        #
        if ( $division_open )
        {
          print $DIVISION $postlude;
          close $DIVISION;
          $division_open = 0;  # false
        }

        push @$ar_section_names,
          { SECTION_NAME   => $section_name,
            DIVISION_NAMES => $ar_current_section_division_names
          };

        ( $section_name = $line_p1 ) =~ s/^.*\"(.*?)\".*[\n\r]*$/$1/o;

        my $stack_last = $#$ar_SECTION_STACK;

        my $section_text = "";
        if ( $stack_last >= 0 )
        {
          $section_text = $$ar_SECTION_STACK[ $stack_last ]{ BODY };
        }

        # Test if previous section had no divisions, e.g. Appendix.
        # And section is not the first.
        # 
        if ( ( ! $first_section ) &&
             ( $division_name eq "" ) &&
             ( scalar( @$ar_current_section_division_names ) == 0 )
           )
        {
          # Here with previous section had no divisions.
          #
          # Test whether previous section was just a heading
          #
          if ( $section_text eq "" )
          {
            # Here with previous section was empty.  ie section is a title only.
            # Keep file for that section open and duplicate text written to
            # sub-sections to this section as well.
            # NB ar_SECTION_STACK[ 0 ] is the base section, other sections nest
            # inside it.
            # For every level of h1 .. h5 etc, open a separate section.
            # Close section on eof or section title found at same level.
            #
            push @$ar_SECTION_STACK,
              { TITLE => $title_level,
                NAME  => "$output_path$report_type-$section_name.$report_format",
                HEAD  => $section_preamble,
                BODY  => ""
              };

            next WRITE_DIVISIONS;
          }
        }

        # Close previous sections if now at numerically same or higher level.
        # (Higher == less important.)
        #
        for ( my $i = $#$ar_SECTION_STACK; $i >= 0; --$i )
        {
          if ( $$ar_SECTION_STACK[ $i ]{ TITLE } >= $title_level )
          {
            my $SECTION = OPEN( ">$$ar_SECTION_STACK[ $i ]{ NAME }" );
            print $SECTION $$ar_SECTION_STACK[ $i ]{ HEAD };
            print $SECTION $$ar_SECTION_STACK[ $i ]{ BODY };
            print $SECTION $postlude;
            close $SECTION;

            pop @$ar_SECTION_STACK;
          }
        }
 
        # Create section
        #
        push @$ar_SECTION_STACK,
          { TITLE => $title_level,
            NAME  => "$output_path$report_type-$section_name.$report_format",
            HEAD  => $section_preamble,
            BODY  => ""
          };

        # For all sections in stack append this section's heading
        #
        for ( my $i = 0; $i <= $#$ar_SECTION_STACK; ++$i )
        {
          $$ar_SECTION_STACK[ $i ]{ BODY } .=  $section_title;
        }

        $first_section = 0;  # false
        $division_name = "";
        $ar_current_section_division_names = [];
      }

      next WRITE_DIVISIONS;
    }
    elsif ( $line =~ /<!--DIVIDER_MARKER:/o )
    {
      # Get sub division name
      #
      ( $division_name = $line ) =~ s/^<!--DIVIDER_MARKER:-->(.*?)<!--END_DIVIDER_MARKER-->.*[\n\r]*$/$1/o;

      $line = "<h3>$division_name</h3>\n";

      push @$ar_current_section_division_names, $division_name;

      # Close any previous division
      #
      if ( $division_open )
      {
        print $DIVISION $postlude;

        close $DIVISION;

        $division_open = 0;  # false
      }

      # Open file for division
      #
      $DIVISION = OPEN( ">$output_path$report_type-$section_name-" .

                        FIX_NAME( $division_name ) .

                        ".$report_format"

                      );

      $division_open = 1;  # true

      print $DIVISION $section_preamble . $section_title;
      $section_title = "";

      $section_preamble = $header;
    }

    if ( $division_open )
    {
      print $DIVISION $line;
    }

    # Is this a section header or the first division in a section?
    #
    if ( scalar( @$ar_current_section_division_names ) <= 1 )
    {
      # Here with section that has no divisions.
      # Append $line to all nested files
      #

      my $stack_last = $#$ar_SECTION_STACK;

      for ( my $i = $stack_last; $i >= 0; --$i )
      {
        $$ar_SECTION_STACK[ $i ]{ BODY } .= $line;
      }
    }
  }

  push @$ar_section_names, { SECTION_NAME => $section_name,
                             DIVISION_NAMES => $ar_current_section_division_names };

  if ( $division_open )
  {
    print $DIVISION $postlude;
    close $DIVISION;
  }

  # Write any unwritten files.
  #
  my $stack_last = $#$ar_SECTION_STACK;
  
  for ( my $i = $stack_last; $i >= 0; --$i )
  {
    my $SECTION = OPEN( ">$$ar_SECTION_STACK[ $i ]{ NAME }" );
    print $SECTION $$ar_SECTION_STACK[ $i ]{ HEAD };
    print $SECTION $$ar_SECTION_STACK[ $i ]{ BODY };
    close $SECTION;
    
    pop @$ar_SECTION_STACK;
  }

#for my $hr_section_name ( @$ar_section_names )
#{
#  print "Section_Name = " . $$hr_section_name{ SECTION_NAME } . "\n";
#
#  my $ar_section_division_names = $$hr_section_name{ DIVISION_NAMES };
#  for my $division_name ( @$ar_section_division_names )
#  {
#    print "   Division_Name = " . $division_name . "\n";
#  }
#}

  #------------------------------------------------------------------------
  #
  # Write report main.
  #

  my $fixed_first_division_file = "";

  my $report_main = "";

  if ( $report_format eq "xhtml" )
  {
    # Here when writing report main for xhtml format.
    #
    $report_main = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" .
                   "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " .
                   "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" .
                   "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n" .
                   "<head>\n" .
                   "<title>$title</title>\n" .
                   "<style type=\"text/css\">\n" .
                   "html, body, div, iframe {overflow:hidden; margin:0; padding:0; height:100%; }\n" .
                   "iframe { display:inline-block; width:100%; border:none; overflow:auto; }\n" .
                   "#leftPane { margin-left:0px; float:left; display:inline-block; width:20%; border:none;  overflow:auto; padding:0px; }\n" .
                   "#rightPane { display:inline-block; width:80%; border:none; ;padding:0px;}\n" .
                   ".majorSection { white-space:nowrap; }\n" .
                   ".subList { display:none; margin-left:20px;height:auto; white-space:nowrap; }\n" .
                   "</style>\n" .
                   "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n";
  }
  elsif ( $report_format eq "html" )
  {
    $report_main = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" " .
                                          "\"http://www.w3.org/TR/html4/loose.dtd\" >\n" .
                   "<head>\n" .
                   "<title>$title</title>\n" .
                   "<style type=\"text/css\">\n" .
                   "html, body, div, iframe {overflow:hidden; margin:0; padding:0; height:100%; }\n" .
                   "iframe { display:inline-block; width:100%; border:none; overflow:auto; }\n" .
                   "#leftPane { margin-left:0px; float:left; display:inline-block; width:20%; border:none;  overflow:auto; padding:0px; }\n" .
                   "#rightPane { display:inline-block; width:80%; border:none; ;padding:0px;}\n" .
                   ".majorSection { white-space:nowrap; }\n" .
                   ".subList { display:none; margin-left:20px;height:auto; white-space:nowrap; }\n" .
                   "</style>\n" .
                   "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" >\n";
  }
  else
  {
    QAR_UTIL::DIEX( "Cannot perform phase 3 processing on file of type .$report_format\n",
                    $main::die_program_termination
                  );
  }

  $report_main .= "<script type=\"text/javascript\" >\n" .
                  "function toggle(id)\n" .
                  "{\n" .
                  "  var display = document.getElementById(id).style.display;\n" .
                  "  document.getElementById(id).style.display = (display != \"block\")?\"block\":\"none\";\n" .
                  "}\n" .
                  "</script>\n" .
                  "</head>\n" .
                  "<body>\n" .
                  "<div id=\"leftPane\"><div style=\"margin-left:15px; overflow:auto; border-right:1px solid #999999;\">\n";

  # Set index into $ar_section_names
  #
  my $section_names_index = -1;

  # Skip preamble to <body>
  #
  my $body_found = 0;  # false
  my $contents_found = 0;  # false

  READ_CONTENTS:
  for my $line ( split( "\n", $preamble ) )
  {
    if ( ! $body_found )
    {
      if ( $line =~ /^<body>$/oi )
      {
        $body_found = 1;  # true
      }
  
      next READ_CONTENTS;
    }
  
    last READ_CONTENTS if ( $line =~ /^\s*<hr>\s*$/oi );

    if ( $line =~ /^<h.>Contents<\/h.>/o )
    {
      $contents_found = 1;  # true

      $report_main .= $line . "\n";
    }
    elsif ( $line =~ /<img/oi )
    {
      # Skip the image from the index text
      #
    }
    elsif ( $line =~ /^<\/?div( class=\"center\"|)>/oi )
    {
      # Skip div specs
      #
    }
    elsif ( $line =~ /^<p>(.*?)<a href=\"#([^\"]*)\">(.*?)</o )
    {
      my $section_number = $1;
      my $section_id_string = $2;
      my $section_title = $3;

      ++$section_names_index;
      my $hr_section = $$ar_section_names[ $section_names_index ];

      if ( $$hr_section{ SECTION_NAME } ne $section_id_string )
      {
        QAR_UTIL::DIEX( "PROGRAM ERROR - Bad section name \"$section_id_string\"",
                        99
                      );
      } 

      my $ar_section_division_names = $$hr_section{ DIVISION_NAMES };
      my $division_name = "";
      if ( scalar( @$ar_section_division_names ) > 0 )
      {
        $division_name = $$ar_section_division_names[ 0 ];
      }

      # Add major section link to contents
      #
      my $fixed_filename = "$report_type-$section_id_string";

      if ( $division_name ne "" )
      {
        $fixed_filename .= FIX_NAME( "-$division_name" );

      }
      $fixed_filename .= ".$report_format";


      if ( $fixed_first_division_file eq "" )

      {
        $fixed_first_division_file = $fixed_filename;

      }

      $report_main .= "<span style=\"white-space:nowrap\"><br/>$section_number<a class=\"majorSection\" " .
                      "href=\"javascript:;\" " .
                      "onclick='javascript:parent.document.getElementById(\"contentFrame\").src=\"" .
                      $fixed_filename . "\";" .

                      "toggle(\"LIST_" . $section_names_index . "\");' >" .
                      "$section_title</a></span>\n";

      $report_main .= "<span class=\"subList\" id=\"LIST_" . $section_names_index . "\" >\n";

      # Add sub division links
      #
      for my $division_name ( @$ar_section_division_names )
      {
        $report_main .= "<br/><a href=\"javascript:;\" ".
                        "onclick='javascript:parent.document.getElementById(\"contentFrame\").src=\"" .
                        "$report_type-$section_id_string-" .

                        FIX_NAME( $division_name ) .

                        ".$report_format" .

                        "\"' >" .

                        "$division_name</a>\n";
      }

      $report_main .= "</span>\n";
    }
    elsif ( ! $contents_found )
    {
      $report_main .= $line . "\n";
    }
  }
  
  $report_main .= "<hr/>" .
                   "</div>" .
                   "</div>" .
                   "<div id=\"rightPane\">" .
                   "<iframe id='contentFrame' src=\"" .

                   $fixed_first_division_file .

                   "\" ></iframe>" .

                   "</div>" .
                   "</body>" .
                   "</html>\n";

  my $MAIN = OPEN( ">$phase_three_result_file" );
  print "Writing $phase_three_result_file\n";
  print $MAIN $report_main;
  close $MAIN;

  #------------------------------------------------------------------------
  #
  # Reports written.  Return name of master main file.
  #
  return $phase_three_result_file;
}

#------------------------------------------------------------------------

sub FIX_NAME
{
  # Usage: $fixed_name = FIX_NAME( $name );

  #
  # Swaps any non OS file characters to _
  #
  my $name = shift;


  # Replace any illegal (file) name characters.

  #
  $name =~ tr/\'\%\+\*\,\?\(\)\=\;\&\@\:\\\/\"\<\>\|/_/;


  return $name;

}

#------------------------------------------------------------------------

sub OPEN
{
  # Usage: $handle = OPEN( $filepath );
  #
  # NB $filepath is prefixed with < or >
  #
  my $filepath = shift;

  my $prefix = substr( $filepath, 0, 1 );
  my $filename = substr( $filepath, 1 );

  QAR_UTIL::TRACE( "OPENING:\n$filepath\n" );


  my $handle;
  open( $handle, $prefix . $filename ) or

    QAR_UTIL::DIEX
      ( "::DIVIDE_REPORT: Cannot open \"$filename\".\n$!",

        $QAR_UTIL::die_program_termination
      );
  
  return $handle;
}

#------------------------------------------------------------------------

1
