/* -*- mode: c++; indent-tabs-mode: nil -*- */
/*
    Pseudo_QC_All.qpp

    Qore Programming Language

    Copyright (C) 2003 - 2023 Qore Technologies, s.r.o.

    Permission is hereby granted, free of charge, to any person obtaining a
    copy of this software and associated documentation files (the "Software"),
    to deal in the Software without restriction, including without limitation
    the rights to use, copy, modify, merge, publish, distribute, sublicense,
    and/or sell copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    DEALINGS IN THE SOFTWARE.

    Note that the Qore library is released under a choice of three open-source
    licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
    information.
*/

#include <qore/Qore.h>
#include "qore/intern/SingleValueIterator.h"

extern QoreClass* QC_SINGLEVALUEITERATOR;

//! Methods in this pseudo-class are available to be executed on any value type (even @ref nothing); this is the root class for all pseudo-classes
/**
 */
qclass <value> [];

//! Returns the type code for the value
/** @par Example:
    @code{.py}
switch (v.typeCode()) {
    case NT_INT:
        printf("%y: is an integer\n", v);
	break;

    case NT_DATE:
        printf("%y: is a date\n", v);
	break;

    default:
        printf("%y: is something else entirely\n", v);
	break;
}
    @endcode

    This method is recommended over <value>::type() or the type(any) or typename(any) functions for comparing data types as it is much faster and more efficient than the other alternatives (which work with string values instead of integer codes).

    @return the type code for the value; see @ref type_code_constants for possible return values for each type

    @see
    - <value>::type()
    - <value>::fullType()
    - <value>::complexType()
 */
int <value>::typeCode() [flags=CONSTANT] {
   return v.getType();
}

//! Returns the string type for the value
/** @par Example:
    @code{.py}
string t = n.type();
    @endcode

    @return the string type for the value; see @ref string_type_constants for possible return values for each type

    @note It is faster and more efficient to use <value>::typeCode() for comparing data types

    @see
    - <value>::typeCode()
    - <value>::fullType()
    - <value>::complexType()
*/
string <value>::type() [flags=CONSTANT] {
   return new QoreStringNode(v.getTypeName());
}

//! returns @ref True if the value has a complex type, @ref False if not
/** @par Example:
    @code{.py}
bool b = n.complexType();
    @endcode

    @return @ref True if the value has a complex type, @ref False if not; if this pseudo-method returns @ref True, then the return value of <value>::fullType() will differ from that of <value>::type()

    Complex types are:
    - @ref hash_hashdecl_type
    - @ref hash_complex_type
    - @ref list_complex_type
    - @ref object_type "objects"

    @see
    - <value>::fullType()
    - <value>::type()
    - <value>::typeCode()

    @since %Qore 0.8.13
*/
bool <value>::complexType() [flags=CONSTANT] {
   return false;
}

//! returns the full type name which differs from the simple type name in case of complex types and objects
/** @par Example:
    @code{.py}
hash <string, int> h();
# returns "hash<string, int>"
string str = n.fullType();
Mutex m();
# returns "object<Mutex>"
str = m.fullType();
    @endcode

    @return the full type name which differs from the simple type name in case of complex types and objects; for simple types the return value is the same as for <value>::type()

    Complex types are:
    - @ref hash_hashdecl_type "hashdecl hashes": the complex type description is returned (ex: \c "hash<MyHash>")
    - @ref hash_complex_type "complex hashes": the complex type description is returned (ex: \c "hash<string, int>")
    - @ref list_complex_type "complex lists": the complex type description is returned (ex: \c "list<int>")
    - @ref object_type "objects": the complex type description is returned (ex: \c "object<MyClass>"; see @ref object_complex_type)

    @see
    - <value>::complexType()
    - <value>::type()
    - <value>::fullType()

    @since
    - %Qore 0.8.13
    - %Qore 1.0 added the \a with_namespaces argument
*/
string <value>::fullType(*bool with_namespaces) [flags=CONSTANT] {
    return new QoreStringNode(v.getFullTypeName(with_namespaces));
}

//! Returns @ref True; this method will be reimplemented in container types where it may return @ref False
/** This pseudo-method will return @ref False in all non-container types; use <value>::val() to check if a generic
    expression that might not be a container type has a value instead.

    @return @ref True; this method will be reimplemented in container types where it may return @ref False

    @par Example:
    @code{.py}
int i = 100;
if (i.empty())
    printf("%y: is empty (probably because it's a value of type %y)\n", i, i.type());
    @endcode

    @see <value>::val()
*/
bool <value>::empty() [flags=CONSTANT] {
   return true;
}

//! Returns zero; this method will be reimplemented in container types where it may return a non-zero value
/** This pseudo-method will return 0 in all non-container types; use <value>::val() to check if a generic
    expression that might not be a container type has a value instead.

    @return zero; this method will be reimplemented in container types where it may return a non-zero value

    @par Example:
    @code{.py}
int i = 100;
if (!i.size())
    printf("%y: has size 0 (probably because it's a value of type %y)\n", i, i.type());
    @endcode

    @see
    - <value>::size()
    - <value>::val()
*/
int <value>::size() [flags=CONSTANT] {
   return 0;
}

//! Returns @ref False; this method is reimplemented in other types and will return @ref True if the given expression has a non-empty value
/**
    @return @ref False; this method is reimplemented in other types and will return @ref True if the given expression has a non-empty value

    @par Example:
    @code{.py}
if (n.val())
    printf("%y: has a non-empty value\n", n);
    @endcode

    @par Rules:
    |!%Type|!Rule
    |@ref int_type "int", @ref float_type "float", @ref number_type "number"|@ref False "False" if zero, @ref True "True" if non-zero
    |@ref string_type "string"|@ref False "False" if empty, @ref True "True" if not empty
    |@ref list_type "list"|@ref False "False" if empty, @ref True "True" if not empty
    |@ref hash_type "hash"|@ref False "False" if empty, @ref True "True" if not empty
    |@ref object_type "object"|always @ref True "True" with a valid object
    |@ref code_type "code"|always @ref True "True"
    |@ref nothing|always @ref False "False"
    |@ref null|always @ref False "False"

    @par Example Values:
    |!Example|!Result
    |@code{.py}0.val()@endcode|@ref False "False"
    |@code{.py}1.val()@endcode|@ref True "True"
    |@code{.py}"".val()@endcode|@ref False "False" (empty string)
    |@code{.py}"0".val()@endcode|@ref True "True"
    |@code{.py}"string".val()@endcode|@ref True "True"
    |@code{.py}().val()@endcode|@ref False "False" (empty list)
    |@code{.py}(0,).val()@endcode|@ref True "True"
    |@code{.py}{}.val()@endcode|@ref False "False" (empty hash)
    |@code{.py}("a":0).val()@endcode|@ref True "True"
    |@code{.py}NOTHING.val()@endcode|@ref False "False"
    |@code{.py}NULL.val()@endcode|@ref False "False"

    @note
    - Use @ref exists to tell if an expression has a value or not
    - This pseudo-method can be used to mimic perl's boolean evaluation when
      @ref strict-bool-eval "%strict-bool-eval" is enabled; the return value of this method
      is the same as that of any value except \c \"0\" when evaluated in a boolean context when
      @ref perl-bool-eval "%perl-bool-eval" is enabled (the default); note that
      <tt>"0".val()</tt> returns @ref True "True" while <tt>boolean("0")</tt>
      returns @ref False "False" in all cases.

    @see
    - @ref perl-bool-eval "%perl-bool-eval"
    - @ref strict-bool-eval "%strict-bool-eval"
*/
bool <value>::val() [flags=CONSTANT] {
   return false;
}

//! Returns @ref False; this method is reimplemented in other types and will return @ref True if the given expression can be converted to an integer
/**
    @return @ref False; this method is reimplemented in other types and will return @ref True if the given expression can be converted to an integer

    @par Example:
    @code{.py}
if (n.intp())
    printf("%y: can be converted to an integer: %d\n", n, int(n));
    @endcode

    @see <string>::intp() for an example of an implementation of this method where the result depends on the value and not the type
*/
bool <value>::intp() [flags=CONSTANT] {
   return false;
}

//! Returns @ref False; this method is reimplemented in other types and will return @ref True if the given expression can be converted to a string
/**
    @return @ref False; this method is reimplemented in other types and will return @ref True if the given expression can be converted to a string

    @par Example:
    @code{.py}
if (n.strp())
    printf("%y: can be converted to a string: '%s'\n", n, string(n));
    @endcode
*/
bool <value>::strp() [flags=CONSTANT] {
   return false;
}

//! Returns @ref False; this method is reimplemented in other types and will return @ref True if the given expression is a callable value (ie @ref closure "closures" or @ref call_reference "call references")
/**
    @return @ref False; this method is reimplemented in other types and will return @ref True if the given expression is a callable value (ie @ref closure "closures" or @ref call_reference "call references")

    @par Example:
    @code{.py}
if (n.callp())
    printf("the reuslt of calling the value: %y\n", n());
    @endcode
*/
bool <value>::callp() [flags=CONSTANT] {
   return false;
}

//! Returns 1; the return value of this method should give the list size of the value, which is normally 1 for non-lists (except for @ref nothing where the size will be 0) and the number of the elements in the list for lists; this method will be reimplemented in other types where it may return other values
/**
    @return 1; the return value of this method should give the list size of the value, which is normally 1 for non-lists (except for @ref nothing where the size will be 0) and the number of the elements in the list for lists; this method will be reimplemented in other types where it may return other values

    @par Example:
    @code{.py}
printf("iterating %d element%s\n", val.lsize(), val.lsize() == 1 ? "" : "s");
foreach any element in (val) {
    do_something(element);
}
    @endcode
*/
int <value>::lsize() [flags=CONSTANT] {
   return 1;
}

//! Returns the string representation of the value; the default is an empty string
/** Use <value>::strp() to determine if the current value can be converted to a string

    @return the string representation of the value; the default is an empty string

    @note check pseudo-classes for each type for other variants of this method; some may take arguments to affect the output format

    @since %Qore 0.8.6
*/
string <value>::toString() [flags=CONSTANT] {
   QoreStringNodeValueHelper str(v);
   return str.getReferencedValue();
}

//! Returns the integer representation of the value; the default is 0
/** Use <value>::intp() to determine if the current value can be converted to an integer

    @return the integer representation of the value; the default is 0

    @since %Qore 0.8.6
*/
int <value>::toInt() [flags=CONSTANT] {
   return v.getAsBigInt();
}

//! Returns the floating-point representation of the value; the default is 0.0
/** @return the floating-point representation of the value; the default is 0.0

    @note if <value>::intp() returns @ref True, then the value can also be converted to a floating-point value

    @since %Qore 0.8.6
*/
float <value>::toFloat() [flags=CONSTANT] {
   return v.getAsFloat();
}

//! Returns the boolean representation of the value; the default is @ref False
/** @return the boolean representation of the value; the default is @ref False

    @note if <value>::intp() returns @ref True, then the value can also be converted to a boolean value

    @since %Qore 0.8.6
*/
bool <value>::toBool() [flags=CONSTANT] {
   return v.getAsBool();
}

//! Returns the arbitrary-precision numeric representation of the value; the default is 0
/** @return the integer representation of the value; the default is 0

    @note if <value>::intp() returns @ref True, then the value can also be converted to an arbitrary-precision numeric value

    @since %Qore 0.8.8
*/
number <value>::toNumber() [flags=CONSTANT] {
   return QoreNumberNode::toNumber(v);
}

//! Returns an iterator object for the value; the default iterator object returned is @ref Qore::SingleValueIterator "SingleValueIterator"
/** @return an iterator object for the value; the default iterator object returned is @ref Qore::SingleValueIterator "SingleValueIterator"

    @par Example:
    @code{.py}
map printf("+ %y\n", $1), v.iterator();
    @endcode

    @since %Qore 0.8.6
 */
AbstractIterator <value>::iterator() [flags=CONSTANT] {
   return new QoreObject(QC_SINGLEVALUEITERATOR, 0, new SingleValueIterator(v));
}

//! Returns @ref True if the type can return a non-zero size (@ref True for containers including @ref binary "binary objects" and @ref string "strings", @ref False for everything else)
/** @return @ref True if the type can return a non-zero size (@ref True for containers including @ref binary "binary objects" and @ref string "strings", @ref False for everything else)

    @see <value>::size()

    @since %Qore 0.8.9
*/
bool <value>::sizep() [flags=CONSTANT] {
   return false;
}

