/* -*- mode: c ; c-file-style: "canonware-c-style" -*-
 ******************************************************************************
 *
 * Copyright (C) 1996-2004 Jason Evans <jasone@canonware.com>.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice(s), this list of conditions and the following disclaimer
 *    unmodified other than the allowable addition of one or more
 *    copyright notices.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice(s), this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 *
 * Version: Onyx 5.1.1
 *
 ******************************************************************************/

#define CW_NXO_C_

#include "../include/libonyx/libonyx.h"
#include "../include/libonyx/nx_l.h"
#include "../include/libonyx/nxa_l.h"
#include "../include/libonyx/nxo_l.h"

/* nxo. */
int32_t
nxo_compare(const cw_nxo_t *a_a, const cw_nxo_t *a_b)
{
    int32_t retval;

    switch (nxo_type_get(a_a))
    {
	case NXOT_ARRAY:
#ifdef CW_OOP
	case NXOT_CLASS:
#endif
#ifdef CW_THREADS
	case NXOT_CONDITION:
#endif
	case NXOT_DICT:
	case NXOT_FILE:
#ifdef CW_HANDLE
	case NXOT_HANDLE:
#endif
#ifdef CW_OOP
	case NXOT_INSTANCE:
#endif
#ifdef CW_THREADS
	case NXOT_MUTEX:
#endif
#ifdef CW_REGEX
	case NXOT_REGEX:
	case NXOT_REGSUB:
#endif
	case NXOT_STACK:
	case NXOT_THREAD:
	{
	    if (nxo_type_get(a_a) == nxo_type_get(a_b)
		&& a_a->o.nxoe == a_b->o.nxoe)
	    {
		retval = 0;
	    }
	    else
	    {
		retval = 1;
	    }
	    break;
	}
	case NXOT_OPERATOR:
	{
	    if (nxo_type_get(a_b) == NXOT_OPERATOR
		&& a_a->o.oper.f == a_b->o.oper.f)
	    {
		retval = 0;
	    }
	    else
	    {
		retval = 1;
	    }
	    break;
	}
	case NXOT_NAME:
	case NXOT_STRING:
	{
	    const char *str_a, *str_b;
	    uint32_t len_a, len_b;
#ifdef CW_THREADS
	    bool lock_a, lock_b;
#endif

	    if (nxo_type_get(a_a) == NXOT_NAME)
	    {
		str_a = nxo_name_str_get(a_a);
		len_a = nxo_name_len_get(a_a);
#ifdef CW_THREADS
		lock_a = false;
#endif
	    }
	    else
	    {
		str_a = nxo_string_get(a_a);
		len_a = nxo_string_len_get(a_a);
#ifdef CW_THREADS
		lock_a = true;
#endif
	    }

	    if (nxo_type_get(a_b) == NXOT_NAME)
	    {
		str_b = nxo_name_str_get(a_b);
		len_b = nxo_name_len_get(a_b);
#ifdef CW_THREADS
		lock_b = false;
#endif
	    }
	    else if (nxo_type_get(a_b) == NXOT_STRING)
	    {
		str_b = nxo_string_get(a_b);
		len_b = nxo_string_len_get(a_b);
#ifdef CW_THREADS
		lock_b = true;
#endif
	    }
	    else
	    {
		retval = 2;
		break;
	    }

#ifdef CW_THREADS
	    if (lock_a)
	    {
		nxo_string_lock((cw_nxo_t *) a_a);
	    }
	    if (lock_b)
	    {
		nxo_string_lock((cw_nxo_t *) a_b);
	    }
#endif
	    if (len_a == len_b)
	    {
		retval = strncmp(str_a, str_b, len_a);
	    }
	    else if (len_a < len_b)
	    {
		retval = strncmp(str_a, str_b, len_a);
		if (retval == 0)
		{
		    retval = -1;
		}
	    }
	    else
	    {
		retval = strncmp(str_a, str_b, len_b);
		if (retval == 0)
		{
		    retval = 1;
		}
	    }
#ifdef CW_THREADS
	    if (lock_b)
	    {
		nxo_string_unlock((cw_nxo_t *) a_b);
	    }
	    if (lock_a)
	    {
		nxo_string_unlock((cw_nxo_t *) a_a);
	    }
#endif
	    break;
	}
	case NXOT_BOOLEAN:
	{
	    if (nxo_type_get(a_b) != NXOT_BOOLEAN)
	    {
		retval = 2;
		break;
	    }

	    if (a_a->o.boolean.val == a_b->o.boolean.val)
	    {
		retval = 0;
	    }
	    else
	    {
		retval = 1;
	    }
	    break;
	}
	case NXOT_INTEGER:
	{
	    switch (nxo_type_get(a_b))
	    {
		case NXOT_INTEGER:
		{
		    if (a_a->o.integer.i < a_b->o.integer.i)
		    {
			retval = -1;
		    }
		    else if (a_a->o.integer.i == a_b->o.integer.i)
		    {
			retval = 0;
		    }
		    else
		    {
			retval = 1;
		    }
		    break;
		}
#ifdef CW_REAL
		case NXOT_REAL:
		{
		    if (((cw_nxor_t) a_a->o.integer.i) < a_b->o.real.r)
		    {
			retval = -1;
		    }
		    else if (((cw_nxor_t) a_a->o.integer.i) == a_b->o.real.r)
		    {
			retval = 0;
		    }
		    else
		    {
			retval = 1;
		    }
		    break;
		}
#endif
		default:
		{
		    retval = 2;
		    break;
		}
	    }
	    break;
	}
#ifdef CW_REAL
	case NXOT_REAL:
	{
	    switch (nxo_type_get(a_b))
	    {
		case NXOT_INTEGER:
		{
		    if (a_a->o.real.r < ((cw_nxor_t) a_b->o.integer.i))
		    {
			retval = -1;
		    }
		    else if (a_a->o.real.r == ((cw_nxor_t) a_b->o.integer.i))
		    {
			retval = 0;
		    }
		    else
		    {
			retval = 1;
		    }
		    break;
		}
		case NXOT_REAL:
		{
		    if (a_a->o.real.r < a_b->o.real.r)
		    {
			retval = -1;
		    }
		    else if (a_a->o.real.r == a_b->o.real.r)
		    {
			retval = 0;
		    }
		    else
		    {
			retval = 1;
		    }
		    break;
		}
		default:
		{
		    retval = 2;
		    break;
		}
	    }
	    break;
	}
#endif
	case NXOT_FINO:
	case NXOT_MARK:
	case NXOT_NULL:
	case NXOT_PMARK:
	{
	    if (nxo_type_get(a_a) == nxo_type_get(a_b))
	    {
		retval = 0;
	    }
	    else
	    {
		retval = 2;
	    }
	    break;
	}
	default:
	{
	    cw_not_reached();
	}
    }

    return retval;
}

cw_nxoe_t *
nxo_nxoe_get(const cw_nxo_t *a_nxo)
{
    cw_nxoe_t *retval;

    cw_check_ptr(a_nxo);
    cw_assert(a_nxo->magic == CW_NXO_MAGIC || nxo_type_get(a_nxo) == NXOT_NO);

    switch (nxo_type_get(a_nxo))
    {
	case NXOT_ARRAY:
#ifdef CW_OOP
	case NXOT_CLASS:
#endif
#ifdef CW_THREADS
	case NXOT_CONDITION:
#endif
	case NXOT_DICT:
	case NXOT_FILE:
#ifdef CW_HANDLE
	case NXOT_HANDLE:
#endif
#ifdef CW_OOP
	case NXOT_INSTANCE:
#endif
#ifdef CW_THREADS
	case NXOT_MUTEX:
#endif
	case NXOT_NAME:
#ifdef CW_REGEX
	case NXOT_REGEX:
	case NXOT_REGSUB:
#endif
	case NXOT_STACK:
	case NXOT_STRING:
	case NXOT_THREAD:
	{
	    retval = a_nxo->o.nxoe;
	    break;
	}
	default:
	{
	    retval = NULL;
	}
    }

    return retval;
}

#ifdef CW_THREADS
bool
nxo_ilocked(cw_nxo_t *a_nxo)
{
    bool retval;

    cw_check_ptr(a_nxo);
    cw_dassert(a_nxo->magic == CW_NXO_MAGIC);

#ifdef CW_DBG
    switch (nxo_type_get(a_nxo))
    {
	case NXOT_ARRAY:
	case NXOT_DICT:
	case NXOT_FILE:
	case NXOT_STACK:
	case NXOT_STRING:
	{
	    retval = a_nxo->o.nxoe->locking;
	    break;
	}
	default:
	{
	    cw_not_reached();
	}
    }
#else
    retval = a_nxo->o.nxoe->locking;
#endif

    return retval;
}
#endif

/* nxoe. */
/* Can be called at any time during nxoe_* initialization. */
void
nxoe_l_new(cw_nxoe_t *a_nxoe, cw_nxot_t a_type, bool a_locking)
{
    /* Initialize the common section. */
    memset(a_nxoe, 0, sizeof(cw_nxoe_t));

    qr_new(a_nxoe, link);
    a_nxoe->type = a_type;
#ifdef CW_THREADS
    a_nxoe->locking = a_locking;
#endif
#ifdef CW_DBG
    a_nxoe->magic = CW_NXOE_MAGIC;
#endif
}
