/// <reference path="HBWedge.ts" />
/// <reference path="../FDNode.ts" />
/// <reference path="../resources/three.d.ts" />
module FD {
    export class HBPoint{
        public x : number;
        public y : number;

        constructor(x:number=0, y:number=0) {
            this.x = x;
            this.y = y;
        }


        public isValid(){
            return (this.d2()<1.0);
        }

        public conjugate(){
            this.y = this.y *-1;
        }


        public multiply (z : any){
            var tx = this.x;
            var ty = this.y;
            this.x = (tx * z.x) - (ty * z.y);
            this.y = (tx * z.y) + (ty * z.x);
        }

        public divide (z : any){
            var d = z.d2();
            var tx = this.x;
            var ty = this.y;
            this.x = ((tx * z.x) + (ty * z.y)) / d;
            this.y = ((ty * z.x) - (tx * z.y)) / d;
        }
    
        
        //Hack for THREE used to be sub
        public subHB(a : HBPoint , b : HBPoint ){
            this.x = a.x - b.x;
            this.y = a.y - b.y;
        }

        public arg(){
            var a = Math.atan(this.y / this.x);

            if (this.x < 0){
              a += Math.PI;
            } else if (this.y < 0){
              a += 2 * Math.PI;
            }
            return a;
        }

        public d2() {
            return (this.x * this.x) + (this.y * this.y);
        }


        public d(p? : HBPoint){
            if(p){
                return Math.sqrt((p.x - this.x) * (p.x - this.x) + (p.y - this.y) * (p.y - this.y));
            }else{
                return Math.sqrt(this.d2());
            }
        }


        //combined two functions to one. If t required set tx and ty to 0 in function call
        public translate(tx?:number, ty?:number, t?:HBPoint){
            if(t){
                var numx = this.x + t.x;
                var numy = this.y + t.y;

                // denominator
                var denx = (this.x * t.x) + (this.y * t.y) + 1.0;
                var deny = (this.y * t.x) - (this.x * t.y) ;    
                
                // division
                var dd = (denx * denx) + (deny * deny);
                this.x = ((numx * denx) + (numy * deny)) / dd;
                this.y = ((numy * denx) - (numx * deny)) / dd;
            }else{
                // numerator
                var numx = this.x + tx;
                var numy = this.y + ty;

                // denominator
                var denx = (this.x * tx) + (this.y * ty) + 1.0;
                var deny = (this.y * tx) - (this.x * ty) ;    
                
                // division
                var dd = (denx * denx) + (deny * deny);
                this.x = ((numx * denx) + (numy * deny)) / dd;
                this.y = ((numy * denx) - (numx * deny)) / dd;
            }
        }

        public specialTrans(alpha:HBPoint, beta:HBPoint){
            // z = (alpha * z + beta) / (conj(alpha) + conj(beta)*z)
            
            var dx = (this.x * beta.x) + (this.y * beta.y) + alpha.x;
            var dy = (this.y * beta.x) - (this.x * beta.y) - alpha.y;
            var d = (dx * dx) + (dy * dy);
            
            var tx = (this.x * alpha.x) - (this.y * alpha.y) + beta.x;
            var ty = (this.x * alpha.y) + (this.y * alpha.x) + beta.y;
            
            this.x = ((tx * dx) + (ty * dy)) / d;
            this.y = ((ty * dx) - (tx * dy)) / d;
        }

        public rotate(theta:HBPoint){
            var px = (this.x * theta.x) + (this.y * theta.y);
            var py = (this.y * theta.x) - (this.x * theta.y);    

            this.x = px;
            this.y = py;
        }

        public toString(){
            return "(" + this.x + " : " + this.y + ")E";
        }

    }
}
