/*
 *  Python extension for reading a Mac OS X plist file.
 *  Copyright (C) 2004  Andreas Junghans <aj@lucid-cake.net>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "cfdate.h"
#include "util.h"
#include "globals.h"


// Returns the time since the epoch used by python (01/01/1970).
static PyObject* timeIntervalSince1970(CFDateObject* self, PyObject* args)
{
    return PyFloat_FromDouble(CFDateGetAbsoluteTime(self->_theDate) +
                              kCFAbsoluteTimeIntervalSince1970);
}


// Returns the time in the format YYYY-MM-DD HH:MM:SS +/-HHMM.
static PyObject* description(CFDateObject* self, PyObject* args)
{
    char desc[30];
    CFTimeZoneRef systemTZ = CFTimeZoneCopySystem();
    CFAbsoluteTime absTime = CFDateGetAbsoluteTime(self->_theDate);
    CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(absTime, systemTZ);
    CFTimeInterval secondsFromGMT = CFTimeZoneGetSecondsFromGMT(systemTZ, absTime);
    CFTimeInterval absSecondsFromGMT = (secondsFromGMT < 0 ? -secondsFromGMT : secondsFromGMT);
    CFRelease(systemTZ);
    sprintf(desc, "%04d-%02d-%02d %02d:%02d:%02d %s%02d%02d",
            (int) date.year,
            (int) date.month,
            (int) date.day,
            (int) date.hour,
            (int) date.minute,
            (int) date.second,
            (secondsFromGMT < 0 ? "-" : "+"),
            (int) (absSecondsFromGMT/3600),
            ((int) absSecondsFromGMT)%3600 / 60
    );
    return PyString_FromString(desc);
}


static PyMethodDef cfdate_methods[] = {
    {"timeIntervalSince1970", (PyCFunction) timeIntervalSince1970, METH_NOARGS, "Returns the time passed since the python epoch."},
    {"description", (PyCFunction) description, METH_NOARGS, "Returns the time in the format YYYY-MM-DD HH:MM:SS +/-HHMM."},
    {NULL, NULL, 0, NULL}
};


static void cfdate_dealloc(CFDateObject* self);
static PyObject* cfdate_new(PyTypeObject* type, PyObject* args, PyObject* kwds);

PyTypeObject cfdate_type = {
    PyObject_HEAD_INIT(&PyType_Type)
    0,
    MODULE_PREFIX CFDATE_NAME,
    sizeof(CFDateObject),
    0,
    (destructor) cfdate_dealloc,
    0,						// tp_print
    0,						// tp_getattr
    0,						// tp_setattr
    0,						// tp_compare
    0,						// tp_repr
    0,						// tp_as_number
    0,						// tp_as_sequence
    0,						// tp_as_mapping
    0,						// tp_hash
    0,						// tp_call
    0,						// tp_str
    0,						// tp_getattro
    0,						// tp_setattro
    0,						// tp_as_buffer
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_CLASS,
    0,						// tp_doc
    0,						// tp_traverse
    0,						// tp_clear
    0,						// tp_richcompare
    0,						// tp_weaklistoffset
    0,						// tp_iter
    0,						// tp_iternext
    cfdate_methods,			// tp_methods
    0,						// tp_members
    0,						// tp_getset
    0,						// tp_base
    0,						// tp_dict
    0,						// tp_descr_get
    0,						// tp_descr_set
    0,						// tp_dictoffset
    0,						// tp_init
    0,						// tp_alloc
    cfdate_new,				// tp_new
};

void cfdate_internalinit(CFDateObject* self, CFDateRef theDate)
{
    CFRetain(theDate);
    self->_theDate = theDate;
}

CFDateObject* cfdate_create(CFDateRef theDate)
{
    CFDateObject* retVal;
    
    retVal = (CFDateObject*) cfdate_type.tp_alloc(&cfdate_type, 0);
    cfdate_internalinit(retVal, theDate);
    
    return retVal;
}

static void cfdate_dealloc(CFDateObject* self)
{
    if (self->_theDate)
    {
        CFRelease(self->_theDate);
    }
    PyObject_Del(self);
}

static PyObject* cfdate_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
{
    PyObject*	pyRetVal;
    CFDateRef	theDate;
    double		absoluteTime;
    
    if (!PyArg_ParseTuple(args, "d", &absoluteTime))
    {
        return NULL;
    }
    theDate = CFDateCreate(NULL, absoluteTime - kCFAbsoluteTimeIntervalSince1970);
    if (theDate == NULL)
    {
        PyErr_SetString(PyExc_MemoryError, "could not allocate a CFDate");
        return NULL;
    }
    pyRetVal = (PyObject*) cfdate_create(theDate);
    CFRelease(theDate);
    return pyRetVal;
}
