using Gee;

public errordomain PhpToValaError {
    UNSUPPORTED
}

public class FunctionBinding : Object {
    public string namespace_name;
    public string package_name;
    public string return_type;
    public bool source_location_args;
    public string? mapped_function_name;
    public ArrayList<string> parameter_types;
    public ArrayList<string?> parameter_defaults;
    public bool native_runtime_only;

    public FunctionBinding (
        string namespace_name,
        string package_name,
        string return_type,
        bool source_location_args,
        string? mapped_function_name = null,
        ArrayList<string>? parameter_types = null,
        ArrayList<string?>? parameter_defaults = null,
        bool native_runtime_only = false
    ) {
        this.namespace_name = namespace_name;
        this.package_name = package_name;
        this.return_type = return_type;
        this.source_location_args = source_location_args;
        this.mapped_function_name = mapped_function_name;
        this.parameter_types = parameter_types ?? new ArrayList<string> ();
        this.parameter_defaults = parameter_defaults ?? new ArrayList<string?> ();
        this.native_runtime_only = native_runtime_only;
    }

    public string call_name (string function_name) {
        return namespace_name + "." + (mapped_function_name ?? function_name);
    }

    public int runtime_parameter_count () {
        int count = runtime_parameter_limit () - runtime_parameter_offset ();
        if (count > 0 && parameter_types[runtime_parameter_limit () - 1].has_suffix ("[]")) {
            return count - 1;
        }
        return count;
    }

    public int runtime_parameter_offset () {
        if (source_location_args
            && parameter_types.size >= 2
            && parameter_types[0] == "string"
            && parameter_types[1] == "int") {
            return 2;
        }
        return 0;
    }

    public int runtime_parameter_limit () {
        if (source_location_args
            && parameter_types.size >= 2
            && !(parameter_types[0] == "string" && parameter_types[1] == "int")) {
            return parameter_types.size - 2;
        }
        return parameter_types.size;
    }

    public int runtime_parameter_index (int arg_index) {
        return runtime_parameter_offset () + arg_index;
    }

    public bool source_location_args_first () {
        return source_location_args && runtime_parameter_offset () == 2;
    }
}

public class LocalParameter : Object {
    public string name;
    public string? type_name;
    public string? default_value;

    public LocalParameter (string name, string? type_name = null, string? default_value = null) {
        this.name = name;
        this.type_name = type_name;
        this.default_value = default_value;
    }
}

public class LocalFunction : Object {
    public string name;
    public ArrayList<LocalParameter> parameters = new ArrayList<LocalParameter> ();
    public string? return_type;
    public string body;
    public int line;
    public bool is_static;
    public string doc_comment;
    public string? static_call_name;
    public string? static_return_type;
    public string? zval_call_name;
    public string? stub_package_name;

    public LocalFunction (string name, ArrayList<LocalParameter> parameters, string? return_type, string body, int line, bool is_static = true, string doc_comment = "") {
        this.name = name;
        this.parameters = parameters;
        this.return_type = return_type;
        this.body = body;
        this.line = line;
        this.is_static = is_static;
        this.doc_comment = doc_comment;
        this.static_call_name = null;
        this.static_return_type = null;
        this.zval_call_name = null;
        this.stub_package_name = null;
    }
}

public class PhpClass : Object {
    public string name;
    public int line;
    public string doc_comment;
    public string extends_name;
    public ArrayList<LocalFunction> methods = new ArrayList<LocalFunction> ();
    public string? pwphpbytecode_loader_symbol;
    public string? pwphpbytecode_stub_source;

    public PhpClass (string name, int line, string doc_comment = "", string extends_name = "") {
        this.name = name;
        this.line = line;
        this.doc_comment = doc_comment;
        this.extends_name = extends_name;
        this.pwphpbytecode_loader_symbol = null;
        this.pwphpbytecode_stub_source = null;
    }
}

public class SourceParts : Object {
    public string main_source = "";
    public ArrayList<LocalFunction> functions = new ArrayList<LocalFunction> ();
    public ArrayList<PhpClass> classes = new ArrayList<PhpClass> ();
}

public class ResolvedSource : Object {
    public string source = "";
    public ArrayList<string> files = new ArrayList<string> ();
    public ArrayList<int> lines = new ArrayList<int> ();
}

public class Statements : Object {
    public ArrayList<string> texts = new ArrayList<string> ();
    public ArrayList<int> lines = new ArrayList<int> ();
    public ArrayList<int> columns = new ArrayList<int> ();
}
