// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompAnying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// See http://www.boost.org/libs/Any for Documentation.
// what:  variant type boost::Any
// who:   contributed by Kevlin Henney,
//        with features contributed and bugs found by
//        Ed Brey, Mark Rodgers, Peter Dimov, and James Curran
// when:  July 2001
//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
//
// Translation to D Programming Language
// (c) Marcin Kuszczak, 2006
//
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

module doost.any.any;

// -----------------------------------------------------------------------------

interface PlaceHolder {
    TypeInfo type();
    PlaceHolder clone();
}

// -----------------------------------------------------------------------------

class Holder(ValueType) : PlaceHolder {
public:
    this(ValueType value) {
        held=value;
    }

    TypeInfo type() {
        return typeid(ValueType);
    }

    PlaceHolder clone() {
        return new Holder(held);
    }

    ValueType held;
}

// -----------------------------------------------------------------------------

class Any {
public:
    this() {
        content=null;
    }

    Any assign(ValueType)(ValueType value) {
        static if (is(ValueType == Any)) content = value.content!=null ? value.content.clone() : null;
            else content=new Holder!(ValueType)(value);
        return this;
    }

    Any swap(Any rhs) {
        PlaceHolder p=content;
        content=rhs.content;
        rhs.content=p;
        return this;
    }

    bool empty() {
        return (content is null);
    }

    TypeInfo type() {
        return content!=null ? content.type() : typeid(void);
    }

private:
    PlaceHolder content;
}

// -----------------------------------------------------------------------------

ValueType anyCast(ValueType)(Any operand) {
    if (operand is null) throw new BadAnyCast(BadAnyCast.NullOperand);
    if (operand.empty) throw new BadAnyCast(BadAnyCast.ValueNotAssigned);
    if (operand.type!=typeid(ValueType)) throw new BadAnyCast(BadAnyCast.InvalidType);

    auto p=cast(Holder!(ValueType))(operand.content);
    return p.held;
}

// -----------------------------------------------------------------------------

class BadAnyCast : Exception {
public:
    enum {NullOperand, ValueNotAssigned, InvalidType};

    this(int reason) {
        char[] msg="BadAnyCast: failed conversion using anyCast";

        switch (reason) {
            case NullOperand : msg~= " - operand is null"; break;
            case ValueNotAssigned: msg~= " - value is not assigned"; break;
            case InvalidType: msg~= " - type of value is different than requested"; break;
            default: break;
        }

        super(msg);
    }

    int reason;
}

