mod test;

use sourcefile::SourceFile as SourceFile;
use dispatch::InvokeReceivier as InvokeReceivier;
use dispatch::Dispatch as Dispatch;
use dispatch::Invoke as Invoke;
use type_name::TypeName as TypeName;
use common::ParseError as ParseError;
use arguments::Argument as Argument;


pub fn compile_dispatch(dispatch: &Box<Dispatch>, sourcefile: &Box<SourceFile>) -> Result<String, ParseError> {
    match dispatch.stack[0].receiver {
        Some(InvokeReceivier::Constant{ref value}) => panic!("not implemented"),
        Some(InvokeReceivier::InstanceObject{ref value}) => panic!("not implemented"),
        Some(InvokeReceivier::TypeObject{ref value}) => return compile_type_invoke(&dispatch.stack[0], &value, &sourcefile),
        _ => panic!("not implemented")
    }
}

fn 
(invoke: &Box<Invoke>, type_name: &Box<TypeName>, sourcefile: &Box<SourceFile>) -> Result<String, ParseError> {
    if ! sourcefile.has_external(type_name.name.clone()) {
        return Err(ParseError::new_msg(&format!("Unkown type {}", type_name.canonical())));
    }
    let external = sourcefile.get_external(&type_name.name).unwrap();
    if ! external.is_roo() {
        let mut output = "".to_string();
        output.push_str(&format!("{}.{}{}(", external.reference_name(), static_call_chain(&invoke), invoke.message_name()));
        output.push_str(&arguments(&invoke));
        output.push_str(");");
        return Ok(output);
    }
    return Ok("".to_string());
}

fn static_call_chain(invoke: &Box<Invoke>) -> String {
    let mut output = "".to_string();
    for (_, static_receiver) in invoke.enumerate_static_receivers() {
        output.push_str(static_receiver);
        output.push_str(".");
    }
    return output;
}

#[allow(unused_variables)]
fn arguments(invoke: &Box<Invoke>) -> String {
    let mut output = "".to_string();
    return match invoke.args {
        None => output,
        Some(ref args) => {
            for (index, arg) in args.enumerate() {
                match *arg {
                    Argument::IntegerArg {ref name, ref value} => {
                        output.push_str(&value.to_string());
                        if index < args.count() - 1 { output.push_str(",") };
                    },
                    Argument::BooleanArg {ref name, ref value} => {
                        output.push_str(&value.to_string());
                        if index < args.count() - 1 { output.push_str(",") };
                    },
                    Argument::DecimalArg {ref name, ref value} => {
                        output.push_str(&value.to_string());
                        if index < args.count() - 1 { output.push_str(",") };
                    },
                    Argument::CharSeqArg {ref name, ref value} => {
                        output.push_str(&format!("\"{}\"", (&value.clone())));
                        if index < args.count() - 1 { output.push_str(",") };
                    },
                    Argument::ObjectArg {ref name, ref value} => {panic!("not implemented");},
                    Argument::DispatchArg {ref name, ref value} => {panic!("not implemented");}
                }
            }
            output
        }
    }
}

compile_type_invoke