// -*- c-basic-offset: 4; related-file-name: "../include/click/handlercall.hh" -*-
/*
 * handlercall.{cc,hh} -- abstracts a call to a handler
 * Eddie Kohler
 *
 * Copyright (c) 2001 International Computer Science Institute
 * Copyright (c) 2004-2006 Regents of the University of California
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, subject to the conditions
 * listed in the Click LICENSE file. These conditions include: you must
 * preserve this copyright notice, and you cannot mention the copyright
 * holders in advertising related to the Software without their permission.
 * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
 * notice is a summary of the Click LICENSE file; the license in that file is
 * legally binding.
 */

#include <click/config.h>
#include <click/handlercall.hh>
#include <click/confparse.hh>
#include <click/router.hh>
#include <click/error.hh>
CLICK_DECLS

int
HandlerCall::initialize(int flags, Element* context, ErrorHandler* errh)
{
    if (!errh)
	errh = ErrorHandler::silent_handler();

    Element *e;
    String hname;
    String value = _value;

    if (initialized()) {
	e = _e;
	hname = _h->name();
	value = _value;
    } else {
	// parse handler name
	if (!cp_handler_name(cp_pop_spacevec(value), &e, &hname, context, errh))
	    return -EINVAL;
	// local handler reference
	if (e->eindex() == -1 && _value[0] != '.' && Router::handler(context, hname))
	    e = context;
    }

    // exit early if handlers not yet defined
    if (!e->router()->handlers_ready())
	return (flags & ALLOW_PREINITIALIZE ? 0 : errh->error("handlers not yet defined"));

    // finish up in assign()
    return assign(e, hname, value, flags, errh);
}

static int
handler_error(Element* e, const String& hname, bool write, ErrorHandler* errh)
{
    if (errh)
	errh->error((write ? "no '%s' write handler" : "no '%s' read handler"), Handler::unparse_name(e, hname).c_str());
    return -ENOENT;
}

int
HandlerCall::assign(Element* e, const String& hname, const String& value, int flags, ErrorHandler* errh)
{
    // find handler
    const Handler* h = Router::handler(e, hname);
    if (!h
	|| ((flags & CHECK_READ) && !h->readable())
	|| ((flags & CHECK_WRITE) && !h->writable()))
	return handler_error(e, hname, flags & CHECK_WRITE /* XXX */, errh);
    else if (value && (flags & CHECK_READ) && !h->read_param()) {
	errh->error("read handler '%s' does not take parameters", Handler::unparse_name(e, hname).c_str());
	return -EINVAL;
    }

    // assign
    _e = e;
    _h = h;
    _value = value;
    return 0;
}

int
HandlerCall::reset(HandlerCall*& call, const String& hdesc, int flags, Element* context, ErrorHandler* errh)
{
    HandlerCall hcall(hdesc);
    int retval = hcall.initialize(flags, context, errh);
    if (retval >= 0) {
	if (!call && !(call = new HandlerCall))
	    return -ENOMEM;
	*call = hcall;
    }
    return retval;
}

int
HandlerCall::reset(HandlerCall*& call, Element* e, const String& hname, const String& value, int flags, ErrorHandler* errh)
{
    HandlerCall hcall;
    int retval = hcall.assign(e, hname, value, flags, errh);
    if (retval >= 0) {
	if (!call && !(call = new HandlerCall))
	    return -ENOMEM;
	*call = hcall;
    }
    return retval;
}

String
HandlerCall::call_read(Element* e, const String& hname, ErrorHandler* errh)
{
    HandlerCall hc;
    String empty;
    if (hc.assign(e, hname, empty, CHECK_READ, errh) >= 0)
	return hc._h->call_read(hc._e, empty, true, errh);
    else
	return empty;
}

int
HandlerCall::call_write(Element* e, const String& hname, const String& value, ErrorHandler* errh)
{
    HandlerCall hc;
    int rv = hc.assign(e, hname, value, CHECK_WRITE, errh);
    return (rv >= 0 ? hc.call_write(errh) : rv);
}


String
HandlerCall::call_read(const String& hdesc, Element* e, ErrorHandler* errh)
{
    HandlerCall hcall(hdesc);
    if (hcall.initialize(CHECK_READ, e, errh) >= 0)
	return hcall.call_read();
    else
	return String();
}

int
HandlerCall::call_write(const String &hdesc, Element *e, ErrorHandler *errh)
{
    HandlerCall hcall(hdesc);
    if (hcall.initialize(CHECK_WRITE, e, errh) >= 0)
	return hcall.call_write(errh);
    else
	return -EINVAL;
}

int
HandlerCall::call_write(const String &hdesc, const String &value, Element *e, ErrorHandler *errh)
{
    HandlerCall hcall(hdesc);
    if (hcall.initialize(CHECK_WRITE, e, errh) >= 0) {
	hcall.set_value(value);
	return hcall.call_write(errh);
    } else
	return -EINVAL;
}

String
HandlerCall::unparse() const
{
    if (ok()) {
	String name = _h->unparse_name(_e);
	if (!_value)
	    return name;
	else
	    return name + " " + _value;
    } else
	return "<bad handler>";
}

CLICK_ENDDECLS


syntax highlighted by Code2HTML, v. 0.9.1