package uuid

import (
	"database/sql/driver"
	"encoding/json"
	"encoding/xml"
	"errors"

	"code.google.com/p/go-uuid/uuid"
)

var InvalidIDError = errors.New("Invalid ID format.")

type ID uuid.UUID

func NewID() ID {
	return ID(uuid.NewRandom())
}

func (id ID) String() string {
	return uuid.UUID(id).String()
}

func (id ID) MarshalJSON() ([]byte, error) {
	return json.Marshal(id.String())
}

func (id ID) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
	return e.EncodeElement(id.String(), start)
}

func (id ID) Value() (driver.Value, error) {
	return id.String(), nil
}

func (id *ID) Scan(src interface{}) error {
	if src == nil {
		id = nil
		return nil
	}
	switch src.(type) {
	case []byte:
		newID, err := Parse(string(src.([]byte)))
		if err != nil {
			return err
		}
		*id = append((*id)[:0], newID...)
		return nil
	case string:
		newID, err := Parse(src.(string))
		if err != nil {
			return err
		}
		*id = append((*id)[:0], newID...)
		return nil
	default:
		return InvalidIDError
	}
	return nil
}

func (id *ID) UnmarshalJSON(in []byte) error {
	var tmp string
	err := json.Unmarshal(in, &tmp)
	if err != nil {
		return err
	}
	newID, err := Parse(tmp)
	if err != nil {
		return err
	}
	*id = append((*id)[:0], newID...)
	return nil
}

func (id *ID) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var tmp string
	err := d.DecodeElement(&tmp, &start)
	if err != nil {
		return err
	}
	newID, err := Parse(tmp)
	if err != nil {
		return err
	}
	*id = append((*id)[:0], newID...)
	return nil
}

func Parse(in string) (ID, error) {
	id := ID(uuid.Parse(in))
	if id == nil {
		return id, InvalidIDError
	}
	return id, nil
}

func (id ID) Equal(other ID) bool {
	return uuid.Equal(uuid.UUID(id), uuid.UUID(other))
}
