/* -*- Mode: javascript; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is mozilla.org calendar code.
 *
 * The Initial Developer of the Original Code is Oracle Corporation
 * Portions created by the Initial Developer are Copyright (C) 2004
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s): Dan Mosedale <dan.mosedale@oracle.com>
 *                 Mike Shaver <mike.x.shaver@oracle.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

/*
 * This file is intended to allow for an easy synchronous interface to 
 * the calendar methods, both for writing tests simply, and for typing at
 * a shell by hand to experiment with calendar methods.  "make calshell" in
 * mozilla/calendar/test (or the equivalent objdir) will start a shell with
 * this code pre-loaded.
 */
 
const C = Components;
const Ci = C.interfaces;
const CC = C.classes;

const evQSvc = getService("@mozilla.org/event-queue-service;1",
                          "nsIEventQueueService");
const evQ = evQSvc.getSpecialEventQueue(Ci.nsIEventQueueService.CURRENT_THREAD_EVENT_QUEUE);

// this is necessary so that the event pump isn't used with providers which
// call the listener before returning, since it would run forever in that case.
var done = false;

function runEventPump()
{
    if (done) { // XXX needed?
        done = false;
        return;
    }
    pumpRunning = true;
    while (pumpRunning) {
        evQ.processPendingEvents();
    }
    done = false; // XXX needed?
    return;
}

function stopEventPump()
{
    pumpRunning = false;
}

// I wonder how many copies of this are floating around
function findErr(result)
{
    for (var i in C.results) {
        if (C.results[i] == result) {
            return i;
        }
    }
    dump("No result code found for " + result + "\n");
}
// I wonder how many copies of this are floating around
function findIface(iface)
{
    for (var i in Ci) {
        if (iface.equals(Ci[i])) {
            return i;
        }
    }
    dump("No interface found for " + iface + "\n");
}

function findOpName(op)
{
    for (var i in Ci.calIOperationListener) {
        if (op == Ci.calIOperationListener[i]) {
            return i;
        }
    }
    dump("Operation type " + op + "unknown\n");
}

function getService(contract, iface)
{
    return C.classes[contract].getService(Ci[iface]);
}

function createInstance(contract, iface)
{
    return C.classes[contract].createInstance(Ci[iface]);
}

function calOpListener() {
}

calOpListener.prototype = 
{
    mItems: [],
    mDetail: null,
    mId: null,
    mStatus: null,

    onOperationComplete: function(aCalendar, aStatus, aOperationType, aId, 
                                  aDetail) {
        stopEventPump();

        this.mDetail = aDetail;
        this.mStatus = aStatus;
        this.mId = aId;

        // XXX verify aCalendar == cal

        done = true;
        return;
    },

    onGetResult: function(aCalendar, aStatus, aItemType, aDetail, aCount, 
                          aItems) {

        // XXX check success(?); dump un-returned data, 

        this.mItems = aItems;

        return;
    }
}

const ioSvc = getService("@mozilla.org/network/io-service;1", "nsIIOService");
 
function URLFromSpec(spec)
{
    return ioSvc.newURI(spec, null, null);
}

/**
 * convenience var/method for setting up the global calendarn "cal"
 */
var cal;
function createCal(type, uri) {
    cal = createInstance("@mozilla.org/calendar/calendar;1?type=" + type,
                         Ci.calICalendar);

    // if a uri has been specified, set it
    if (uri) {
        cal.uri = URLFromSpec(calendarUri);
    }

    return;
}

/**
 * convenience method to create an item and potentially initialize it from ICS
 */
function createItem(icalString) {

    var item = createInstance("@mozilla.org/calendar/event;1", Ci.calIEvent);
    if (icalString) {
        item.icalString = "icalString";
    }

    return item;
}

/**
 * convenience wrappers around various calICalendar methods so that shell 
 * callers don't have to deal with the listener
 */
function addItem(item) {
    done = false;
    var listener = new calOpListener();
    cal.addItem(item, listener);
    runEventPump();

    if (!C.isSuccessCode(listener.mStatus)) {
        throw new Exception(listener.mStatus, listener.mDetail);
    }
    return listener.mDetail.QueryInterface(Ci.calIItemBase);
}

function getItem(id) {
    done = false;
    var listener = new calOpListener();
    cal.getItem(id, listener);
    runEventPump();

    if (!C.isSuccessCode(listener.mStatus)) {
        throw new Exception(listener.mStatus, listener.mDetail);
    }
    return listener.mItems[0];
}

function getItems(filter, count, rangeStart, rangeEnd) {
    done = false;
    var listener = new calOpListener();
    cal.getItems(filter, count, rangeStart, rangeEnd, listener);
    runEventPump();

    if (!C.isSuccessCode(listener.mStatus)) {
        throw new Exception(listener.mStatus, listener.mDetail);
    }
    return listener.mItems;
}

function deleteItem(item) {
    done = false;
    var listener = new calOpListener();
    cal.deleteItem(item, listener);
    runEventPump();

    if (!C.isSuccessCode(listener.mStatus)) {
        throw new Exception(listener.mStatus, listener.mDetail);
    }
    return listener.mId;
}
