#
# Functions for printing XML items
#

use warnings;
use strict;

# Return the min/max scale denominators

sub get_scale_from_zoom
  {
   my($zoom)=(@_);

   my(%zooms)=(
                0 => 1000000000,
                1 => 500000000,
                2 => 200000000,
                3 => 100000000,
                4 => 50000000,
                5 => 25000000,
                6 => 12500000,
                7 => 6500000,
                8 => 3000000,
                9 => 1500000,
               10 => 750000,
               11 => 400000,
               12 => 200000,
               13 => 100000,
               14 => 50000,
               15 => 25000,
               16 => 12500,
               17 => 5000,
               18 => 2500,
               19 => 1500,
               20 => 750,
               21 => 500,
               22 => 250,
               23 => 100
              );

   return ($zooms{$zoom},$zooms{$zoom+1});
  }


# Print a rule

sub print_rule
  {
   my($FILE,$global,$rule)=(@_);

   print $FILE "  <Rule>\n";

   if($rule->{filter} ne "")
     {
      print $FILE "    <Filter>$rule->{filter}</Filter>\n";
     }

   my($symboliser);

   foreach $symboliser (@{$rule->{symbolisers}})
     {
      print $FILE "    <$symboliser->{name}";

      my($parameter);

      foreach $parameter (sort (keys %{$symboliser->{parameters}}))
        {
         print $FILE " $parameter='$symboliser->{parameters}{$parameter}'";
        }

      if(defined $symboliser->{content})
        {
         print $FILE ">$symboliser->{content}</$symboliser->{name}>\n";
        }
      else
        {
         print $FILE " />\n";
        }
     }

   print $FILE "  </Rule>\n";
  }


# Print a style

sub print_style
  {
   my($FILE,$global,$style)=(@_);

   print $FILE "<Style name='$style->{name}' filter-mode='first'>\n";

   my($rule);

   foreach $rule (@{$style->{rules}})
     {
      print_rule($FILE,$global,$global->{rules}[$rule]);
     }

   print $FILE "</Style>\n";
  }


# Print a layer (and associated styles)

sub print_layer
  {
   my($FILE,$global,$layer)=(@_);

   return if($#{$layer->{styles}} == -1);

   my($first,$style)=1;

   foreach $style (@{$layer->{styles}})
     {
      if($first)
        {
         print $FILE "\n";
         print $FILE "<!-- Styles required for $layer->{description} layer for zoom $layer->{zoom} -->\n";
         print $FILE "\n";

         $first=0;
        }

      print_style($FILE,$global,$global->{styles}[$style]);
     }

   print $FILE "\n";
   print $FILE "<!-- The $layer->{description} layer for zoom $layer->{zoom} -->\n";
   print $FILE "\n";

   print $FILE "<Layer name='$layer->{name}'";

   if(defined $layer->{srs})
     {
      print $FILE " srs='$layer->{srs}'";
     }

   my($maxscale,$minscale)=get_scale_from_zoom($layer->{zoom});

   print $FILE " maxzoom='$maxscale'" if($maxscale);
   print $FILE " minzoom='$minscale'" if($minscale);

   print $FILE " cache-features='true'";

   if(defined $layer->{'group-by'})
     {
      print $FILE " group-by='$layer->{'group-by'}'";
     }

   print $FILE ">\n";

   foreach $style (reverse (@{$layer->{styles}}))
     {
      print $FILE "  <StyleName>$global->{styles}[$style]{name}</StyleName>\n";
     }

   if(defined $layer->{'datasource-base'} && $layer->{'datasource-base'} eq "postgis" &&
      !defined $layer->{datasource}{table})
     {
      my(@filters)=();

      my(%allcolumns)=();
      my(%primecolumns)=();

      foreach $style (@{$layer->{styles}})
        {
         my($rule);

         foreach $rule (@{$global->{styles}[$style]{rules}})
           {
            if($global->{rules}[$rule]{filter} ne "")
              {
               push(@filters,$global->{rules}[$rule]{filter});
              }

            my($symboliser);

            foreach $symboliser (@{$global->{rules}[$rule]{symbolisers}})
              {
               if($symboliser->{name} eq "TextSymbolizer" || $symboliser->{name} eq "ShieldSymbolizer")
                 {
                  # This following line must use quotes or it will never match for point-polygon rules.
                  if("$symboliser->{content}" =~ m%\[([^]]+)\]%g)
                    {
                     $allcolumns{$1}=1;
                    }
                 }
              }
           }
        }

      my(%primevalues)=();
      my($filter,$subfilter,$subfilter0);

      foreach $filter (@filters)
        {
         my(@subfilters)=($filter =~ m%\(([^)]+)\)%g);

         my(@subfilters0)=split(/ +(and|or) +/,$subfilters[0]);

         foreach $subfilter0 (@subfilters0)
           {
            next if($subfilter0 eq "and");
            next if($subfilter0 eq "or");

            if($subfilter0 =~ m%^\[([^]]+)\] *= *(['"][^'"]+['"])$%g)
              {
               $allcolumns{$1}=1;
               $primecolumns{$1}{$2}=1;
              }
            elsif($subfilter0 =~ m%^\[([^]]+)\] *!= *(['"]['"])$%g)
              {
               $allcolumns{$1}=1;
               $primecolumns{$1}{NOT}=1;
              }
            else
              {
               print Dumper(@subfilters0);

               die "FILTER has invalid format or comparison (only [x]='y' and/or [x]!='') are allowed).\n";
              }
           }

         foreach $subfilter (@subfilters)
           {
            while($subfilter =~ m%\[([^]]+)\]%g)
              {
               $allcolumns{$1}=1;
              }
           }
        }

      my($sql)="(SELECT way";

      my($column);

      foreach $column (sort (keys %allcolumns))
        {
         if($column eq "natural" || $column =~ m%:%)
           {
            $column="\"$column\"";
           }

         if($column eq "tunnel" || $column eq "bridge" || $column eq "disused" || $column eq "area" || $column eq "capital")
           {
            $sql.=",\n        CASE WHEN $column IS null OR $column IN ('no','false','0') THEN 'no'::text ELSE 'yes'::text END AS $column";
           }
         elsif($column eq "oneway")
           {
            $sql.=",\n        CASE WHEN $column IS null OR $column IN ('no','false','0') THEN 'no'::text WHEN $column IN ('yes','true','1') THEN '1'::text WHEN $column IN ('-1') THEN '-1'::text ELSE 'no'::text END AS $column";
           }
         elsif(defined $allcolumns{"${column}_length"})
           {
            $sql.=",\n        $column, char_length($column) AS ${column}_length";
           }
         elsif($column =~ m%_length$%)
           {
           }
         else
           {
            $sql.=",\n        $column";
           }
        }

      if(defined $layer->{'extra-sql-column-clause'})
        {
         $sql.=",\n        $layer->{'extra-sql-column-clause'}";
        }

      $sql.="\n FROM $layer->{'sql-table'}\n";
      $sql.=" WHERE";

      my($number_or_clauses)=0;

      foreach $column (sort (keys %primecolumns))
        {
         $number_or_clauses++;
        }

      if(defined $layer->{'extra-sql-where-clause'})
        {
         $sql.="\n";
         $sql.="      ($layer->{'extra-sql-where-clause'}) AND";

         if($number_or_clauses>1)
           {
            $sql.="\n      (";
           }
        }

      my($first)=1;

      foreach $column (sort (keys %primecolumns))
        {
         my($original_column)=$column;

         if($column eq "natural" || $column =~ m%:%)
           {
            $column="\"$column\"";
           }

         $sql.=" OR" if(!$first);

         if(defined $primecolumns{$original_column}{NOT})
           {
            $sql.="\n       $column IS NOT null";
           }
         else
           {
            $sql.="\n       $column IN (".join(',',(sort (keys %{$primecolumns{$original_column}}))).")";
           }

         $first=0;
        }

      if(defined $layer->{'extra-sql-where-clause'} && $number_or_clauses>1)
        {
         $sql.="\n      )";
        }

      $sql.="\n";

      if(defined $layer->{'extra-sql-order-clause'})
        {
         $sql.=" ORDER BY $layer->{'extra-sql-order-clause'}\n";
        }

      $sql.=") AS data\n";

      $layer->{datasource}{table}="<![CDATA[\n$sql]]>";
     }

   if(defined $layer->{'datasource-base'})
     {
      print $FILE "  <Datasource base='$layer->{'datasource-base'}'>\n";
     }
   else
     {
      print $FILE "  <Datasource>\n";
     }

   my($parameter);

   foreach $parameter (sort (keys %{$layer->{datasource}}))
     {
      print $FILE "    <Parameter name='$parameter'>$layer->{datasource}{$parameter}</Parameter>\n";
     }

   print $FILE "  </Datasource>\n";

   print $FILE "</Layer>\n";
  }


# Print an XML header

sub print_header
  {
   my($FILE,$global)=(@_);

   print $FILE "<?xml version='1.0' encoding='utf-8'?>\n";
   print $FILE "<!DOCTYPE Map[]>\n";

   print $FILE "<Map";

   my($parameter);

   foreach $parameter (sort (keys %{$global->{mapinfo}}))
     {
      print $FILE " $parameter='$global->{mapinfo}{$parameter}'";
     }

   print $FILE ">\n";

   print $FILE "\n";

   print $FILE "<Parameters>\n";

   foreach $parameter (sort (keys %{$global->{parameters}}))
     {
      print $FILE "  <Parameter name='$parameter'>$global->{parameters}{$parameter}</Parameter>\n";
     }

   print $FILE "</Parameters>\n";
   print $FILE "\n";

   my($fontset,$font);

   foreach $fontset (@{$global->{fontsets}})
     {
      print $FILE "<FontSet name='$fontset->{name}'>\n";

      foreach $font (@{$fontset->{fonts}})
        {
         print $FILE "  <Font face-name='$font'/>\n";
        }

      print $FILE "</FontSet>\n";
     }

   print $FILE "\n";

   my($filesource);

   foreach $filesource (@{$global->{filesources}})
     {
      print $FILE "<FileSource name='$filesource->{name}'>$filesource->{dir}</FileSource>\n";
     }

   print $FILE "\n";

   my($key);

   foreach $key (sort (keys %{$global->{datasources}}))
     {
      print $FILE "<Datasource name='$key'>\n";

      foreach $parameter (sort (keys %{$global->{datasources}{$key}}))
        {
         print $FILE "  <Parameter name='$parameter'>$global->{datasources}{$key}{$parameter}</Parameter>\n";
        }

      print $FILE "</Datasource>\n";

      print $FILE "\n";
     }
  }


# Print an XML body section

sub print_body
  {
   my($FILE,$global,$zoom)=(@_);

   my($first,$layer)=1;

   foreach $layer (@{$global->{layers}})
     {
      if($layer->{zoom}==$zoom)
        {
         if($first)
           {
            print $FILE "\n";
            print $FILE "<!-- - - - - - - - - - - Styles and Layers for zoom $zoom - - - - - - - - - - -->\n";
            print $FILE "\n";

            $first=0;
           }

         print_layer($FILE,$global,$layer);
        }
     }
  }


# Print an XML footer

sub print_footer
  {
   my($FILE,$global)=(@_);

   print $FILE "\n";
   print $FILE "</Map>\n";
  }


#
1;
