
# single RDF propertie, can be a set of allowed values
# (per example, the description attribute for photoRDF 
# pictures
module RDFProperty
    attr_reader :name, :rdf_property
    attr_accessor :namespace
    def many_choice?
        @multiple
    end
end

class RDFMultipleChoice < Gtk::Frame
    include RDFProperty
    attr_reader :exif_properties
    def initialize name, rdf_property, allowed_values = nil
        super name
        @name = name
        @rdf_property = rdf_property
        @multiple = true

        self.shadow_type = Gtk::ShadowType::ETCHED_OUT

        @exif_properties = nil

        @state = Hash.new

        hb = Gtk::HBox.new
        y = 0
        flip = 1

        inner_table = Gtk::Table.new 1, 1, false

        allowed_values.each{ |rdf_name, real_name|
            cb = Gtk::CheckButton.new real_name
            puts "RDF name is #{rdf_name}"
            @state[rdf_name] = cb

            if flip==1
                inner_table.attach cb, 0, 2, y, y+1
            else
                inner_table.attach cb, 2, 3, y, y+1
                y = y+1
            end 
            flip *= -1
        }
        hb.pack_start inner_table
        self.add hb
    end
    def value
        objects = Hash.new
        temp = Array.new
        objects[@namespace+rdf_property] = Array.new
        @state.each{ |rdf_name, gtk_checkbox|
            if gtk_checkbox.active?
                temp << rdf_name
            end
        }
        objects[@namespace+rdf_property] = temp.join(", ")
        return objects
    end
    def to_rdf model, subject
        value().each{ |ns,content|
            predicate = model.resource(ns)
            object = model.literal(content)
            model.statement(subject, predicate, object)
        }
    end
    def value=(val)
        values = val.split(/, /)
        self.clear
        values.each{ |value|
            @state[value.downcase].active = true
        }

        puts "RDFMultipleChoice : "+val
        # TODO: handle this !
    end
    def clear
        @state.each{ |k,v|
            v.active = false
        }
    end
    def attach table_widget, y
        table_widget.attach self, 0, 3, y, y+1
        table_widget.show_all
    end
end



class RDFTableInputItem < Gtk::Table
    include RDFProperty
    attr_reader :gtk_label, :gtk_input
    attr_reader :is_resource, :exif_properties

    def initialize name, rdf_property, exif_properties = nil
        super 1,1, false
        @name = name
        @rdf_property = rdf_property
        @multiple = false 
        @namespace = namespace

        @exif_properties = exif_properties

        @is_resource = false

        
        @gtk_label = Gtk::Label.new name
        
        tooltipg = Gtk::Tooltips.new
        @cb = Gtk::CheckButton.new
        tooltipg.set_tip(@cb, "Fix this value", nil)

        self.blocked=false

        @cb.signal_connect("button-press-event") do 
            |w,e|
            # the new state is set after this callback
            self.blocked=!w.active?
            false
        end
       self.show_all 
    end
    def blocked=(value)
        @blocked = value
        if value==true
            @gtk_input.editable = false
            #@gtk_input.state = Gtk::StateType::INSENSITIVE
        else
            @gtk_input.state = Gtk::StateType::NORMAL
            #@gtk_input.editable = true
        end
    end
    def to_rdf model, subject
        self.value().each do |ns,content|
            predicate = model.resource( ns ) 
            if @is_resource
                object = model.resource( content )
            else
                object = model.literal( content )
            end
            model.statement( subject, predicate, object )
        end
    end
    def value
        raise "This is an interface, please overload me"
    end
    def value=(val)
        raise "This is an interface, please overload me"
    end
    def clear
        raise "This is an interface, please overload me"
    end
    def focus
        @gtk_input.grab_focus
    end
    def attach table_widget, y
        table_widget.attach @gtk_label, 0, 1, y, y+1
        table_widget.attach @cb, 1, 2, y, y+1
        table_widget.attach @gtk_input, 2, 3, y, y+1
    end
end

class RDFTableItem < RDFTableInputItem
    def initialize name, rdf_property, exif_properties = nil
        @gtk_input = Gtk::Entry.new
        @gtk_input.signal_connect("insert-text") do |widget, ntext, position, data|
            #ntext is the new text typed
            text = widget.text + ntext
            if @is_resource == false && text =~ /^http:\/\//
                @is_resource = true
                @gtk_label.set_text(@gtk_label.text + " [res]")    
            elsif text !~ /^http:\/\//
                @gtk_label.set_text(@gtk_label.text.gsub(/ \[res\]/,''))    
                @is_resource = false
            end
        end
        super
    end
    def value
        text = @gtk_input.text
        if text != ""
            objects = Hash.new
            objects[@namespace+@rdf_property] = text
        else
            objects = {}
        end
        return objects
    end
    def value=(val)
        if !@blocked
            @gtk_input.text = val
        end
    end
    def clear
        if !@blocked
            @gtk_input.text = ''
        end
    end 
end

# multiline widget
class RDFTableTextarea < RDFTableInputItem
    def initialize name, rdf_property, exif_properties = nil
        @tb = Gtk::TextBuffer.new
        @multiline = true
        @gtk_input = Gtk::TextView.new(@tb)
        @gtk_input.set_wrap_mode(2)
        @gtk_input.height_request = 100

        
        super
    end
    def value
        text = @tb.get_text(@tb.get_iter_at_offset(0),@tb.get_iter_at_offset(-1),false)
        if text != ""
            objects = Hash.new
            objects[@namespace+@rdf_property] = text
        else
            objects = {}
        end
        return objects
    end
    def value=(val)
        if !@blocked
            @tb.set_text(val)
        end
    end
    def clear
        if !@blocked
            @tb.set_text('')
        end
    end 
end


module RDFRepresentation
    attr_reader :namespace, :locator, :name
    attr_accessor :page
    attr_reader :content
    attr_reader :exif_locator
    # namespace it the RDF namespace URI
    def setup( namespace, meaningful_name )

        @inner_table = Gtk::Table.new 1,1,false

        @namespace = namespace
        @name = meaningful_name
        @content = Array.new
        @locator = Hash.new
        @exif_locator = Hash.new

        @y = 0
    end
    def push table_item
        return self << table_item
    end
    def << table_item
        @content << table_item
        @locator[table_item.rdf_property] = table_item
        if table_item.exif_properties != nil
            table_item.exif_properties.each { |ep|
                @exif_locator[ep] = table_item
            }
        end
        
        # setup the namespace
        table_item.namespace = @namespace

        table_item.attach @inner_table, @y
        @y += 1
        
        return self
    end
    def create
        return self
    end
    def [](property)
        if @locator.has_key?(property)
            return @locator[property]
        else
            puts "Unknown property #{property}"
            # this is an unknow property
            # display it !
            self << RDFTableItem.new(property+" [added]", property)
            self.show_all
            return @locator[property]
        end
        #raise UnknowPropertyException.new("Unknown property '#{property}'")
    end
    def []=(property,value)
        lo = self[property]
        lo.value = value
    end
    def clear
        @locator.each{ |k,v|
            v.clear
        }
    end
end


# this table represents a set of multiple properties for a given namespace
class RDFEnumeration < Gtk::VBox
    include RDFRepresentation
    def initialize( namespace, meaningful_name)
        super()
        #set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
        setup(namespace, meaningful_name)
        pack_start Gtk::Label.new(namespace)
        pack_start @inner_table
        show_all()
    end 
    def create
        #add_with_viewport(@inner_table)
        return self
    end
end
module RDFNsList
    attr_reader :exif_locator

    def setup
        @my_hash = Hash.new
    end

    def <<(rdf_enumeration)
        raise "Namespace '#{namespace}' already used" if @my_hash.has_key?(rdf_enumeration.namespace)
        @my_hash[rdf_enumeration.namespace] = rdf_enumeration
        @exif_locator ||= Hash.new
        @exif_locator.update rdf_enumeration.exif_locator
        return self
    end
    def each
        @my_hash.each{ |k,v|
            yield v
        }
    end
    def []=(ns, prop, value)
       if !@my_hash.has_key?(ns)
           new_ns = RDFEnumeration.new( ns, ns+' [added]' )
           self << new_ns
           puts "Creating namespace #{ns}"
           #raise NSException.new("Unknow namespace '#{ns}'")
       end
        @my_hash[ns][prop] = value
        return self
    end
    def clear
        @my_hash.each{ |k,v|
            v.clear if v!=nil
        }
        return self
    end
    def get_widget
        raise "Not implemented"
    end
end

# RDFPane
# @panes
class RDFFrame
    include RDFNsList
    def initialize
        setup
        @frame = Gtk::ScrolledWindow.new
        @vbox = Gtk::VBox.new false, 0
        @frame.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC)
        @current_position = 0
    end
    def <<(rdf_enumeration)
        super(rdf_enumeration)
        rdf_enumeration.page = @current_position
        frame = Gtk::Frame.new rdf_enumeration.name
        frame.shadow_type = Gtk::ShadowType::ETCHED_OUT
        frame.add rdf_enumeration


        @vbox.pack_start frame, false, true, 0
        @vbox.show_all
        @current_position += 1
    end
    def get_widget

        @frame.add_with_viewport @vbox
        return @frame
    end
    def focus element
        each{ |ns|
            if ns.locator.has_key?(element)
                ns.locator[element].focus
            end
        }
    end
end

class RDFNoteBook
    include RDFNsList
    def initialize
        setup
        @notebook = Gtk::Notebook.new
        @current_page = 0
    end
    def <<(rdf_enumeration)
        super(rdf_enumeration)
        rdf_enumeration.page = @current_page
        @notebook.append_page rdf_enumeration,
		Gtk::Label.new(rdf_enumeration.name)

        @current_page += 1
    end
    def get_widget
        return @notebook
    end
    def focus element
        each{ |ns|
            if ns.locator.has_key?(element)
                @notebook.set_page(ns.page)
                ns.locator[element].focus
            end
        }
    end
end
