// This file is autogenerated. Do not edit.
// To make some changes, edit codegen.rb and run make

use std::io::MemReader;
use framing::{FrameType, Frame};
use amqp_error::AMQPResult;


pub trait Method {
    fn decode(method_frame: MethodFrame) -> AMQPResult<Self>;
    fn encode(&self) -> Vec<u8>;
    fn name(&self) -> &'static str;
    fn id(&self) -> u16;
    fn class_id(&self) -> u16;
}


#[deriving(Show, Clone)]
pub struct MethodFrame {
    pub class_id: u16,
    pub method_id: u16,
    pub arguments: Vec<u8>
}

impl MethodFrame {
    pub fn encode_method<T>(method: &T) -> Vec<u8> where T: Method {
        let frame = MethodFrame {class_id: method.class_id(), method_id: method.id(), arguments: method.encode()};
        frame.encode()
    }
    pub fn encode(&self) -> Vec<u8> {
        let mut writer = vec!();
        writer.write_be_u16(self.class_id).unwrap();
        writer.write_be_u16(self.method_id).unwrap();
        writer.write(self.arguments.as_slice()).unwrap();
        writer
    }

    // We need this method, so we can match on class_id & method_id
    pub fn decode(frame: Frame) -> MethodFrame {
        if frame.frame_type != FrameType::METHOD {
            panic!("Not a method frame");
        }
        let mut reader = MemReader::new(frame.payload);
        let class_id = reader.read_be_u16().unwrap();
        let method_id = reader.read_be_u16().unwrap();
        let arguments = reader.read_to_end().unwrap();
        MethodFrame { class_id: class_id, method_id: method_id, arguments: arguments}
    }

    pub fn method_name(&self) -> &'static str {
        match (self.class_id, self.method_id) {
<% matches.each do |m| -%>
          <%= m %>,
<% end -%>
          (_,_) => "UNKNOWN"
        }
    }
}


<% classes.each do |klass| %>
#[allow(unused_imports)]
pub mod <%= klass["name"] %> {
    use std::collections::bitv;
    use std::collections::bitv::Bitv;
    use std::io::MemReader;
    use table;
    use table::{Table, decode_table, encode_table};
    use protocol::{Method, MethodFrame};
    use framing::ContentHeaderFrame;
    use amqp_error::{AMQPResult, AMQPError};


<% if klass["properties"] && klass["properties"].any? -%>
    //properties struct for <%= klass["name"] %>
    #[deriving(Show, Default, Clone)]
    pub struct <%= klass["properties_struct_name"] %> {
<% klass["properties_fields"].join(",\n").split("\n").each do |f| -%>
       <%= f %>
<% end -%>
    }

    impl <%= klass["properties_struct_name"] %> {
        pub fn decode(content_header_frame: ContentHeaderFrame) -> AMQPResult<<%=klass["properties_struct_name"]%>> {
            let mut reader = MemReader::new(content_header_frame.properties);
            let properties_flags = bitv::from_bytes(&[((content_header_frame.properties_flags >> 8) & 0xff) as u8,
                (content_header_frame.properties_flags & 0xff) as u8]);
<% klass["properties"].each.with_index do |prop, idx| -%>
            let <%= prop["prop_name"] %> = if properties_flags.get(<%= idx %>) {
                Some(<%=read_type(prop["prop_type"])%>)
            } else {
                None
            };
<% end -%>
            Ok(<%=klass["properties_struct_name"]%> { <%= klass["properties_struct_create"].join(", ") %> })
        }

        pub fn encode(self) -> Vec<u8> {
            let mut writer = vec!();
<% klass["properties"].each.with_index do |prop, idx| -%>
              match self.<%= prop["prop_name"] %> {
                  Some(prop) => {
                      let <%= prop["prop_name"] %> =  prop;
                      <%= write_type(prop["prop_name"], prop["prop_type"]) %>
                  }
                  None => {}
              };
<% end -%>
            writer
        }

        pub fn flags(&self) -> u16 {
            let mut bits = Bitv::with_capacity(16, false);
<% klass["properties"].each.with_index do |prop, idx| -%>
            bits.set(<%= idx %>, self.<%= prop["prop_name"] %>.is_some());
<% end -%>
            let flags : u16 = bits.to_bytes()[0] as u16;
            (flags << 8 | bits.to_bytes()[1] as u16) as u16
        }
    }
<% end -%>

<% klass["methods"].each do |method| -%>
    // Method <%= method["id"] %>:<%=method["name"] %>
    #[deriving(Show)]
<% if method["fields"].any? -%>
    pub struct <%= method["method_name"] %> {
<% method["fields"].join(",\n").split("\n").each do |f| -%>
        <%= f %>
<% end -%>
    }
<% else -%>
    pub struct <%= method["method_name"] %>;
<% end -%>

    impl Method for <%= method["method_name"] %> {
        fn name(&self) -> &'static str {
            "<%= klass["name"] %>.<%= method["name"] %>"
        }

        fn id(&self) -> u16 {
            <%= method["id"] %>
        }

        fn class_id(&self) -> u16 {
            <%= klass["id"] %>
        }

        fn decode(method_frame: MethodFrame) -> AMQPResult<<%= method["method_name"] %>> {
            match (method_frame.class_id, method_frame.method_id) {
                (<%= klass["id"] %>, <%= method["id"] %>) => {},
                (_,_) => {return Err(AMQPError::DecodeError("Frame class_id & method_id didn't match"))}
            };
<% if method["arguments"].any? -%>
<% method["readers"].each do |reader| -%>
            <%= reader %>
<% end -%>
            Ok(<%= method["method_name"]%> { <%= method["method_struct_create"].join(", ")  %> })
<% else -%>
            Ok(<%= method["method_name"]%>)
<% end -%>
          }

        fn encode(&self) -> Vec<u8> {
<% if method["arguments"].any? -%>
<% method["writers"].each do |writer| -%>
            <%= writer %>
<% end -%>
<% else -%>
            vec!()
<% end -%>
        }
    }

<% if method["arguments"].any? && method["arguments"].count{|arg| arg["default-value"]} > 0 -%>
    impl <%= method["method_name"] %> {
        pub fn with_default_values(<%= args_list(method["arguments"].reject{|arg| arg["default-value"]}).join(", ") %>) -> <%= method["method_name"] %> {
            <%= method["method_name"] %> {
<% method["arguments"].select{|arg| arg["default-value"]}.each do |arg| -%>
                <%= snake_name(arg["name"]) %>: <%= value_to_rust_value(arg["default-value"]) %>,
<% end -%>
<% method["arguments"].reject{|arg| arg["default-value"]}.each do |arg| -%>
                <%= snake_name(arg["name"]) %>: <%= snake_name(arg["name"]) %>,
<% end -%>
            }
        }
    }
<% end #method["arguments"].any-%>

<% end #methods each-%>
}
<% end #classes each -%>