using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;

namespace CSGBuilder {
    [Serializable()]
    public class Matrix : ISerializable {
        // sorok és oszlopok száma
        int rows, cols;
        // a mátrix
        double[,] m;

        public Matrix(int r, int c) {
            rows = r; cols = c;
            m = new double[r, c];
        }
        
        public double this[int r, int c] {
            get {
                if (r >= 0 && r < rows && c >= 0 && c < cols) return m[r, c];
                else return 0.0;
            }
            set {
                if (r >= 0 && r < rows && c >= 0 && c < cols)
                    m[r, c] = value;
            }
        }

        #region ISerializable Members

        public void GetObjectData(SerializationInfo info, StreamingContext context) {
            info.AddValue("Rows", rows);
            info.AddValue("Cols", cols);
            info.AddValue("Data", m);
        }

        public Matrix(SerializationInfo info, StreamingContext context) {
            rows = info.GetInt32("Rows");
            cols = info.GetInt32("Cols");
            m = (double[,])info.GetValue("Data", typeof(double[,]));
        }

        #endregion

        // Feltölti nullákkal a mátrixot
        public void LoadZero() {
            for (int i = 0; i < rows; i++)
                for (int j = 0; j < cols; j++)
                    m[i, j] = 0.0;
        }

        // Egységmátrixot készít
        public void LoadIdentity() {
            LoadZero();
            for (int i = 0; i < rows; i++)
                m[i, i] = 1.0;
        }

        // Két mátrix összege
        static public Matrix operator +(Matrix orig, Matrix k) {
            Matrix result = new Matrix(orig.rows, orig.cols);
            for (int i = 0; i < orig.rows; i++)
                for (int j = 0; j < orig.cols; j++)
                    result[i, j] = orig[i, j] + k[i, j];
            return result;
        }

        // Két mátrix különbsége
        static public Matrix operator -(Matrix orig, Matrix k) {
            Matrix result = new Matrix(orig.rows, orig.cols);
            for (int i = 0; i < orig.rows; i++)
                for (int j = 0; j < orig.cols; j++)
                    result[i, j] = orig[i, j] - k[i, j];
            return result;
        }

        // Két mátrix szorzata
        static public Matrix operator *(Matrix a, Matrix b) {
            Matrix result = new Matrix(a.rows, b.cols);
            for (int i = 0; i < a.rows; i++)
                for (int j = 0; j < b.cols; j++) {
                    result[i, j] = 0.0f;
                    for (int k = 0; k < a.cols; k++)
                        result[i, j] += a[i, k] * b[k, j];
                }
            return result;
        }

        // Mátrix és vektor szorzata
        public static Matrix operator *(Matrix m, Point3D p) {
            Matrix r = new Matrix(4, 1);
            r[0, 0] = p.X;
            r[1, 0] = p.Y;
            r[2, 0] = p.Z;
            r[3, 0] = 1.0;
            return m * r;
        }

        // Mátrix transzponáltja
        public Matrix Trans() {
            Matrix x = new Matrix(cols, rows);
            for (int i = 0; i < rows; i++)
                for (int j = 0; j < cols; j++)
                    x[j, i] = m[i, j];
            return x;
        }

        // Mátrixból 3D vektor (első oszlop)
        public Point3D ToPoint3Dh() {
            return new Point3D(m[0, 0], m[1, 0], m[2, 0]);
        }

        // Mátrixból 2D vektor (első oszlop)
        public System.Drawing.Point ToPoint2D() {
            return new System.Drawing.Point((int)m[0, 0], (int)m[1, 0]);
        }

    }
}
