#!/usr/local/bin/ruby

#######################################
# Perscrib2svg
#
# A simple hack at creating a simple SVG file
# (Scalable Vector Graphic file format: http://www.w3.org/Graphics/SVG/ )
# from the strokes stored by Prescribble.
#
# The resulting SVG can then be viewed/converted/whatever with
# SVG tools, such as Batik from the XML efforts of Apache
# (Batik: http://xml.apache.org/batik/ requires Java)
#
# Other requirements: 
# - Ruby ( http://www.lang-ruby.org )
# - NQXML ( http://www.io.com/~jimm/downloads/nqxml/index.html )



require 'nqxml/streamingparser'

module Prescribble


##
#  Loads the given XML filename with stores the strokes
#  of a Prescribble data file and returns
#  an array of the notebooks.
#
#  notebooks = array of notebooks, notebook = array of notes,
#  note = array of strokes, stroke = array of points, 
#  point = [x,y]       
#

def Prescribble::loadPrescribbleStrokes( filename )

        notebooks = []
        currentnotebook = nil
        currentnote = nil
        currentstroke = nil

        
        tagaction = {
        "notebook" => proc{ currentnotebook = Array.new
                        notebooks.push(currentnotebook) },
        "note" => proc{ currentnote = Array.new
                        currentnotebook.push(currentnote) },
        "stroke" => proc{ currentstroke = Array.new
                          currentnote.push(currentstroke) },
        "newpoint" => proc{|point| 
                                currentstroke.push(point) if currentstroke
                        },
        }
        
        result = parsePrescribbleFile( filename, tagaction )
        if(result)
                notebooks
        else
                nil
        end

end #loadPrescribble

def Prescribble::parsePrescribbleFile( filename, tagaction )

    errorSeen = false
    parser = NQXML::StreamingParser.new(File.open(filename))
    begin


        parser.each { | entity | 
                #p entity
                # puts "entity: " + entity.name

                if entity.kind_of?( NQXML::Tag )  #&& !entity.isTagEnd
                       action = if entity.isTagEnd
                                        tagaction[("/"+entity.name)]
                       else
                                        tagaction[entity.name]
                       end
                       action.call if action        
                elsif entity.kind_of?( NQXML::Text )
                        entity.source.split(' ').each{|coord|
                                m = /[0-9]*,[0-9]*/.match(coord)
                                
                                if (m)
                                        point = []
                                        m.to_s.split(",").each{|s|
                                                point.push(s.to_i)
                                        }
                                        
                                        tagaction["newpoint"].
                                                call(point)

                                end
                        }
                end



        }

    rescue NQXML::ParserError
        print "\n  NQXML parser error, line #{parser.line}: #{$!}"
        errorSeen = true
        retry
    rescue
        print "\n  Non-parser error: #{$!}"
        errorSeen = true
    end 
    return !errorSeen                           
        
end #parsePrescribbleFile


#end #Prescribble module





#module PrescribbleSVG



SVG_BEGIN = '<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000802//EN"
"http://www.w3.org/TR/2000/CR-SVG-20000802/DTD/svg-20000802.dtd">
'

SVG_HEADER = '<svg width="WIDTH"' + 
' height="HEIGHT">
<title>TITLE</title><g> '  


SVG_END = "</g></svg>
"

##
# hiddeously bad method for saving SVG files from the strokes
#

def Prescribble::saveSVGFile( notebooks, filename )
agendaheight = 240
agendawidth = 160
a4pagewidth = 4
a4pageheight= 4

notepage = 0
basex = 0
basey = 0

File.open(filename, "w"){|out|




notebooks.each{|book| 
        puts "Book:"


  out.print SVG_BEGIN


  out.print SVG_HEADER.gsub("WIDTH", (agendawidth*a4pagewidth).to_s).
                gsub("HEIGHT", (agendaheight*a4pageheight).to_s).
                gsub("TITLE", "Prescribble notes")


        book.each{|note|
                puts "  Note:"
                basey = agendaheight* ((notepage/a4pagewidth).to_i)
                basex = agendawidth*  ((notepage%a4pagewidth).to_i)

                #surrounding rectangle?

                out.print '<g style="fill:white; stroke:gray; stroke-width:1;">                                        
<rect  x="' + basex.to_s +  
'" y="' + basey.to_s +
'" width="' + agendawidth.to_s + 
'" height="' + agendaheight.to_s + '"/></g>
'



               
                note.each{|stroke|

                        out.print '<path 
   style="fill:none; stroke:black; stroke-width:1; "
   d="M '

                        stroke.each{|point|
                                x,y = point
                                x = x + basex
                                y = y + basey  
                                s = x.to_s + " " + y.to_s + " " 
                                out.print s           
                        }

                        out.print '" />'
                }
                notepage +=1
        }

 out.print SVG_END #"</g></svg>"
}
} #File

end #saveSVGFile method


##########################
#
#
#

def Prescribble::prescribble2SVG( filename )
agendaheight = 240
agendawidth = 160
a4pagewidth = 4
a4pageheight= 4

notepage = 0
basex = 0
basey = 0

puts "Beginning processing ... (this may take a while)"

File.open(filename+".svg", "w"){|out|

  out.print SVG_BEGIN


  out.print SVG_HEADER.gsub("WIDTH", (agendawidth*a4pagewidth).to_s).
                gsub("HEIGHT", (agendaheight*a4pageheight).to_s).
                gsub("TITLE", "Prescribble notes")

  tagaction = { 
        "note"=>proc{
                basey = agendaheight* ((notepage/a4pagewidth).to_i)
                basex = agendawidth*  ((notepage%a4pagewidth).to_i)
                out.print '<g style="fill:white; stroke:gray; stroke-width:1;">  '+
                '<rect  x="' + basex.to_s +  
                '" y="' + basey.to_s +
                '" width="' + agendawidth.to_s + 
                '" height="' + agendaheight.to_s + '"/></g>
'
                notepage+=1;


        }, 
        "stroke"=>proc{

                out.print '<path '+
                'style="fill:none; stroke:black; stroke-width:1; " '+
                'd="M '

        },
        "/stroke"=>proc{
                        out.print '" />'
        },
        "newpoint"=>proc{|point|
                                x,y = point
                                x = x + basex
                                y = y + basey  
                                s = x.to_s + " " + y.to_s + " " 
                                out.print s           
        },
  }

  parsePrescribbleFile( filename, tagaction )

  out.print SVG_END 

}

end



end #Prescribble module




# Main part

filename = ARGV[0]





if filename
#        notebooks = Prescribble::loadPrescribbleStrokes( filename )
#        Prescribble::saveSVGFile( notebooks, filename+".svg" )

        Prescribble::prescribble2SVG( filename )

else
        puts "prescrib2svg: need filename of input Prescribble strokes data file."

end
