# -*- coding: utf-8 -*-
#
# AWL data types helper functions
#
# Copyright 2013-2019 Michael Buesch <m@bues.ch>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

from awlsim.common.cython_support cimport *


cdef extern from "<endian.h>":		#@cy-posix
cdef extern from "endian-win.h":	#@cy-win
	enum: BYTE_ORDER
	enum: LITTLE_ENDIAN
	enum: BIG_ENDIAN

	uint16_t htobe16(uint16_t)
	uint16_t htole16(uint16_t)
	uint16_t be16toh(uint16_t)
	uint16_t le16toh(uint16_t)

	uint32_t htobe32(uint32_t)
	uint32_t htole32(uint32_t)
	uint32_t be32toh(uint32_t)
	uint32_t le32toh(uint32_t)

cdef extern from "<byteswap.h>":	#@cy-posix
cdef extern from "byteswap-win.h":	#@cy-win
	uint16_t bswap_16(uint16_t)
	uint32_t bswap_32(uint32_t)


cdef inline uint16_t swapEndianWord(uint16_t word):
	return bswap_16(word)

cdef inline uint32_t swapEndianDWord(uint32_t dword):
	return bswap_32(dword)


cdef inline int32_t byteToSignedPyInt(uint8_t byte):
	return <int32_t>(<int8_t>byte)

cdef inline int32_t wordToSignedPyInt(uint16_t word):
	return <int32_t>(<int16_t>word)

cdef inline int32_t dwordToSignedPyInt(uint32_t dword):
	return <int32_t>dword

cdef inline int64_t qwordToSignedPyInt(uint64_t qword):
	return <int64_t>qword


cdef union _floatCastUnion:
	float fvalue
	uint32_t value32

cdef uint32_t pyFloatToDWord(double pyfl)

cdef inline double dwordToPyFloat(uint32_t dword):
	cdef _floatCastUnion u
	u.value32 = dword
	return <double>(u.fvalue)


cdef class FloatConst(object):
	cdef public uint32_t minNormPosFloat32DWord
	cdef public double minNormPosFloat32

	cdef public uint32_t minNormNegFloat32DWord
	cdef public double minNormNegFloat32

	cdef public uint32_t maxNormNegFloat32DWord
	cdef public double maxNormNegFloat32

	cdef public uint32_t maxNormPosFloat32DWord
	cdef public double maxNormPosFloat32

	cdef public uint32_t posInfDWord
	cdef public double posInfFloat

	cdef public uint32_t negInfDWord
	cdef public double negInfFloat

	cdef public uint32_t pNaNDWord

	cdef public uint32_t nNaNDWord
	cdef public double nNaNFloat

	cdef public uint32_t negZeroDWord

	cdef public double epsilonFloat

cdef public FloatConst floatConst


cdef inline _Bool isNaN(uint32_t dword):
	return (dword & 0x7FFFFFFFu) > 0x7F800000u

cdef inline _Bool isInf(uint32_t dword):
	return (dword & 0x7FFFFFFFu) == 0x7F800000u

cdef inline _Bool isPosNegZero(uint32_t dword):
	return (dword & 0x7FFFFFFFu) == 0u

cdef inline _Bool isDenormalPyFloat(double pyfl):
	return ((pyfl > 0.0 and pyfl < floatConst.minNormPosFloat32) or
	        (pyfl < 0.0 and pyfl > floatConst.maxNormNegFloat32))

cdef inline _Bool pyFloatEqual(double pyfl0, double pyfl1):
	return abs(pyfl0 - pyfl1) < floatConst.epsilonFloat

cdef _Bool floatEqual(object fl0, object fl1)


cdef inline uint32_t roundUp(uint32_t n, uint32_t s):
	return ((n + s - 1u) // s) * s

cdef inline uint32_t intDivRoundUp(uint32_t n, uint32_t d):
	return (n + d - 1u) // d

cdef uint32_t getMSB(uint32_t value)


cdef inline _Bool isInteger(object value):
	return isinstance(value, int)

cdef inline _Bool isString(object value):
	return isinstance(value, str)

cdef inline uint32_t len_u32(object obj):
	return <uint32_t>(min(len(obj), <object>0xFFFFFFFFu))

cdef inline uint16_t len_u16(object obj):
	return <uint16_t>(min(len(obj), <object>0xFFFFu))

cdef inline uint8_t len_u8(object obj):
	return <uint8_t>(min(len(obj), <object>0xFFu))

cdef inline int32_t len_s32(object obj):
	return <int32_t>(min(len(obj), <object>0x7FFFFFFFu))

cdef inline int16_t len_s16(object obj):
	return <int16_t>(min(len(obj), <object>0x7FFFu))

cdef inline int8_t len_s8(object obj):
	return <int8_t>(min(len(obj), <object>0x7Fu))

cdef inline int32_t u32_to_s32(uint32_t value):
	return <int32_t>(min(value, 0x7FFFFFFFu))

cdef inline int16_t u32_to_s16(uint32_t value):
	return <int16_t>(min(value, 0x7FFFu))

cdef inline int8_t u32_to_s8(uint32_t value):
	return <int8_t>(min(value, 0x7Fu))

cdef inline uint32_t s32_to_u32(int32_t value):
	return <uint32_t>(max(value, 0))

cdef inline uint16_t s32_to_u16(int32_t value):
	return <uint16_t>(min(max(value, 0), 0xFFFF))

cdef inline uint8_t s32_to_u8(int32_t value):
	return <uint8_t>(min(max(value, 0), 0xFF))
