/* **********************************************************************************
 *
 * Copyright (c) Microsoft Corporation. All rights reserved.
 *
 * This source code is subject to terms and conditions of the Shared Source License
 * for IronPython. A copy of the license can be found in the License.html file
 * at the root of this distribution. If you can not locate the Shared Source License
 * for IronPython, please send an email to ironpy@microsoft.com.
 * By using this source code in any fashion, you are agreeing to be bound by
 * the terms of the Shared Source License for IronPython.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * **********************************************************************************/

using System;
using System.Collections.Generic;
using System.Text;

using IronMath;

namespace IronPython.Runtime {
    public static partial class IntOps {
        #region Generated IntOps

        // *** BEGIN GENERATED CODE ***


        [PythonName("__add__")]
        public static object Add(int x, object other) {
            if (other is int) {
                int y = (int)other;
                try {
                    return Ops.Int2Object(checked(x + y));
                } catch (OverflowException) {
                    return BigInteger.Create(x) + y;
                }
            } else if (other is BigInteger) {
                return BigInteger.Create(x) + (BigInteger)other;
            } else if (other is double) {
                return x + (double)other;
            } else if (other is Complex64) {
                return ComplexOps.Add(Complex64.MakeReal(x), other);
            } else if (other is bool) {
                bool b = (bool)other;
                return x + (b ? 1 : 0);
            } else if (other is long) {
                long y = (long)other;
                try {
                    return checked(x + y);
                } catch (OverflowException) {
                    return BigInteger.Create(x) + y;
                }
            } else if (other is float) {
                return x + (float)other;
            } else if (other is byte) {
                return x + (byte)other;
            }
            return Ops.NotImplemented;
        }


        [PythonName("__sub__")]
        public static object Subtract(int x, object other) {
            if (other is int) {
                int y = (int)other;
                try {
                    return Ops.Int2Object(checked(x - y));
                } catch (OverflowException) {
                    return BigInteger.Create(x) - y;
                }
            } else if (other is BigInteger) {
                return BigInteger.Create(x) - (BigInteger)other;
            } else if (other is double) {
                return x - (double)other;
            } else if (other is Complex64) {
                return ComplexOps.Subtract(Complex64.MakeReal(x), other);
            } else if (other is bool) {
                bool b = (bool)other;
                return x - (b ? 1 : 0);
            } else if (other is long) {
                long y = (long)other;
                try {
                    return checked(x - y);
                } catch (OverflowException) {
                    return BigInteger.Create(x) - y;
                }
            } else if (other is float) {
                return x - (float)other;
            } else if (other is byte) {
                return x - (byte)other;
            }
            return Ops.NotImplemented;
        }


        [PythonName("__mul__")]
        public static object Multiply(int x, object other) {
            if (other is int) {
                int y = (int)other;
                try {
                    return Ops.Int2Object(checked(x * y));
                } catch (OverflowException) {
                    return BigInteger.Create(x) * y;
                }
            } else if (other is BigInteger) {
                return BigInteger.Create(x) * (BigInteger)other;
            } else if (other is double) {
                return x * (double)other;
            } else if (other is Complex64) {
                return ComplexOps.Multiply(Complex64.MakeReal(x), other);
            } else if (other is bool) {
                bool b = (bool)other;
                return x * (b ? 1 : 0);
            } else if (other is long) {
                long y = (long)other;
                try {
                    return checked(x * y);
                } catch (OverflowException) {
                    return BigInteger.Create(x) * y;
                }
            } else if (other is float) {
                return x * (float)other;
            } else if (other is byte) {
                return x * (byte)other;
            }
            return Ops.NotImplemented;
        }


        [PythonName("__floordiv__")]
        public static object FloorDivide(int x, object other) {
            if (other is int) {
                int y = (int)other;
                try {
                    return Ops.Int2Object(Divide(x, y));
                } catch (OverflowException) {
                    return LongOps.Divide(BigInteger.Create(x) , y);
                }
            } else if (other is BigInteger) {
                return LongOps.Divide(BigInteger.Create(x), (BigInteger)other);
            } else if (other is double) {
                double y = (double)other;

                if(y == 0) throw Ops.ZeroDivisionError();

                return x / y;
            } else if (other is Complex64) {
                Complex64 y = (Complex64)other;
                if(y.IsZero) throw Ops.ZeroDivisionError();

                return ComplexOps.FloorDivide(Complex64.MakeReal(x), y);
            } else if (other is bool) {
                bool b = (bool)other;
                return x / (b ? 1 : 0);
            } else if (other is long) {
                long y = (long)other;
                try {
                    return Divide(x, y);
                } catch (OverflowException) {
                    return LongOps.Divide(BigInteger.Create(x), y);
                }
            } else if (other is float) {
                float y = (float)other;
                if(y == 0) throw Ops.ZeroDivisionError();

                return x / y;
            } else if (other is byte) {
                return x / (byte)other;
            }
            return Ops.NotImplemented;
        }


        [PythonName("__div__")]
        public static object TrueDivide(int x, object other) {
            if (other is int) {
                return TrueDivide(x, (int)other);
            }
            return Ops.NotImplemented;
        }


        [PythonName("__mod__")]
        public static object Mod(int x, object other) {
            if (other is int) {
                int y = (int)other;
                try {
                    return Ops.Int2Object(Mod(x, y));
                } catch (OverflowException) {
                    return LongOps.Mod(BigInteger.Create(x) , y);
                }
            } else if (other is BigInteger) {
                return LongOps.Mod(BigInteger.Create(x), (BigInteger)other);
            } else if (other is double) {
                double y = (double)other;

                if(y == 0) throw Ops.ZeroDivisionError();

                return x % y;
            } else if (other is Complex64) {
                Complex64 y = (Complex64)other;
                if(y.IsZero) throw Ops.ZeroDivisionError();

                return ComplexOps.Mod(Complex64.MakeReal(x), y);
            } else if (other is bool) {
                bool b = (bool)other;
                return x % (b ? 1 : 0);
            } else if (other is long) {
                long y = (long)other;
                try {
                    return Mod(x, y);
                } catch (OverflowException) {
                    return LongOps.Mod(BigInteger.Create(x), y);
                }
            } else if (other is float) {
                float y = (float)other;
                if(y == 0) throw Ops.ZeroDivisionError();

                return x % y;
            } else if (other is byte) {
                return x % (byte)other;
            }
            return Ops.NotImplemented;
        }


        [PythonName("__and__")]
        public static object BitwiseAnd(int x, object other) {
            if (other is int) {
                return Ops.Int2Object(x & (int)other);
            } else if (other is long) {
                long lx = (long)x;
                return lx & (long)other;
            } else if (other is BigInteger) {
                return BigInteger.Create(x) & (BigInteger)other;
            }
            return Ops.NotImplemented;
        }


        [PythonName("__or__")]
        public static object BitwiseOr(int x, object other) {
            if (other is int) {
                return Ops.Int2Object(x | (int)other);
            } else if (other is long) {
                long lx = (long)x;
                return lx | (long)other;
            } else if (other is BigInteger) {
                return BigInteger.Create(x) | (BigInteger)other;
            }
            return Ops.NotImplemented;
        }


        [PythonName("__xor__")]
        public static object Xor(int x, object other) {
            if (other is int) {
                return Ops.Int2Object(x ^ (int)other);
            } else if (other is long) {
                long lx = (long)x;
                return lx ^ (long)other;
            } else if (other is BigInteger) {
                return BigInteger.Create(x) ^ (BigInteger)other;
            }
            return Ops.NotImplemented;
        }


        // *** END GENERATED CODE ***

        #endregion

    }
}
