
//manage map "views" or "envelopes"

// -------------------------- CLASSES

function IMS2_Envelope(x1,y1,x2,y2){
    var self = this;
    
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    
    function toString(){
        return("{(" + self.x1 + "," + self.y1 + "),(" + self.x2 + "," + self.y2 + ")}");
    }
    this.toString = toString;
    
    function IsPoint(){
        if((self.x1 == self.x2) && (self.y1 == self.y2)){
            return(true);
        }
        return(false);
    }
    this.IsPoint = IsPoint;
    
    function GetWidth(){
        if(self.x1 > self.x2){
            return(self.x1 - self.x2);
        }
        return(self.x2 - self.x1);
    }
    this.GetWidth = GetWidth;
    
    function GetHeight(){
        if(self.y1 > self.y2){
            return(self.y1 - self.y2);
        }
        return(self.y2 - self.y1);
    }
    this.GetHeight = GetHeight;
    
    function GetLeft(){
        if(self.x1 > self.x2){
            return(self.x2);
        }
        return(self.x1);
    }
    this.GetLeft = GetLeft;
    
    function GetTop(){
        if(self.y1 > self.y2){
            return(self.y2);
        }
        return(self.y1);
    }
    this.GetTop = GetTop;
    
    function Copy(){
        return(new IMS2_Envelope(self.x1,self.y1,self.x2,self.y2));
    }
    this.Copy = Copy;
    
    function CopyScaled(sw,sh){
        var nenv = new IMS2_Envelope(self.x1,self.y1,self.x2,self.y2);
        if(nenv){
            nenv.ScaleDimensions(sw,sh);
        }
        return(nenv);
    }
    this.CopyScaled = CopyScaled
    
    function ScaleDimensions(sw,sh){
        var hw = self.GetWidth() * 0.5;
        var hh = self.GetHeight() * 0.5;
        var cx = self.GetLeft() + hw;
        var cy = self.GetTop() + hh;
        hw *= (sw);
        hh *= (sh);
        this.x1 = cx - hw;
        this.x2 = cx + hw;
        this.y1 = cy - hh;
        this.y2 = cy + hh;
    }
    this.ScaleDimensions = ScaleDimensions;
    
    function SetCenter(x,y)
    {
        var hw = self.GetWidth() * 0.5;
        var hh = self.GetHeight() * 0.5;
        self.x1 = x - hw;
        self.y1 = y - hh;
        self.x2 = x + hw;
        self.y2 = y + hh;
    }
    this.SetCenter = SetCenter;

    function MoveCenter(dx,dy)
    {
        if(0 != dx || 0 != dy){
            var x = (self.GetLeft() + (self.GetWidth() * 0.5)) + dx;
            var y = (self.GetTop() + (self.GetHeight() * 0.5)) + dy;
            self.SetCenter(x,y);
        }
    }
    this.MoveCenter = MoveCenter;
    
    function PanUnitCircle(dx,dy,dist){
        self.MoveCenter(dx * dist,dy * dist);
    }
    this.PanUnitCircle = PanUnitCircle;
    
    function PanRadians(theta,dist){
        if(Math){
            dx = Math.cos(theta);
            dy = Math.sin(theta);
            self.PanUnitCircle(dx,dy,dist);
        }
    }
    this.PanRadians = PanRadians;
    
    function PanCardinal(dir,dist){
        var dx = 0;
        var dy = 0;
        if(0 == dir || 4 == dir){ // N
            dy = 1;
            dx = 0;
        }else if(0.5 == dir){ // NE
            dx = 0.707106781;
            dy = 0.707106781;
        }else if(1 == dir){ // E
            dx = 1;
            dy = 0;
        }else if(1.5 == dir){ // SE
            dx = 0.707106781;
            dy = -0.707106781;
        }else if(2 == dir){ // S
            dx = 0;
            dy = -1;
        }else if(2.5 == dir){ // SW
            dx = -0.707106781;
            dy = -0.707106781;
        }else if(3 == dir){ // W
            dx = -1;
            dy = 0;
        }else if(3.5 == dir){ // NW
            dx = -0.707106781;
            dy = 0.707106781;
        }
        self.PanUnitCircle(dx,dy,dist);
    }
    this.PanCardinal = PanCardinal;
}

function IMS2_View(x1,y1,x2,y2,imgw,imgh){
    var self = this;
    
    this.env = new IMS2_Envelope(x1,y1,x2,y2);
    this.imgw = imgw;
    this.imgh = imgh;
    
    function toString(){
        return("{(" + self.imgw + "," + self.imgh + ")," + self.env + "}");
    }
    this.toString = toString;
    
    function Copy(){
        var nv = null;
        if(self.env){
            nv = new IMS2_View(self.env.x1,self.env.y1,self.env.x2,self.env.y2,self.imgw,self.imgh);
        }
        return(nv);
    }
    this.Copy = Copy;
    
    function RawScale(){
        var scale = -1;
        if(self.env && self.imgw){
            if(self.imgw != 0){
                scale = (self.env.GetWidth() / self.imgw);
            }
        }
        return(scale);
    }
    this.RawScale = RawScale;
    
    function PanCardinal(dir,dist){
        if(self.env){
            self.env.PanCardinal(dir,dist);
        }
    }
    this.PanCardinal = PanCardinal;
    
    function PanRadians(theta,dist){
        if(self.env){
            self.env.PanRadians(theta,dist);
        }
    }
    this.PanRadians = PanRadians;
    
    function Pan(dx,dy){
        if(self.env){
            self.env.MoveCenter(dx,dy);
        }
    }
    this.Pan = Pan;
    
    function Zoom(zs){
        ;
    }
    this.Zoom = Zoom;
    
    function ResizeImage(nimgw,nimgh,scaleView){
        if(scaleView){
            var ws = (self.imgw != 0) ? (nimgw / self.imgw) : (1);
            var hs = (self.imgh != 0) ? (nimgh / self.imgh) : (1);
            if(self.env){
                self.env.ScaleDimensions(ws,hs);
            }
        }
        self.imgw = nimgw;
        self.imgh = nimgh;
    }
    this.ResizeImage = ResizeImage;
    
    function SetImageSize(w,h){
        self.imgw = w;
        self.imgh = h;
    }
    this.SetImageSize = SetImageSize;
    
    function SetEnvelope(x1,y1,x2,y2){
        this.env = new IMS2_Envelope(x1,y1,x2,y2);
    }
    this.SetEnvelope = SetEnvelope;
}


//control "zoom previous" and "zoom next"
function IMS2_ViewHistory(maxHistorySize){
    var self = this;
    
    this.views = new Array();
    this.maxHistory = (maxHistorySize) ? (maxHistorySize) : 100;
    this.curView = 0;
    
    function toString(){
        var outStr = "";
        if(self.views){
            outStr += "history (" + self.GetCount() + "):";
            for(var i = 0;i < self.views.length; i++){
                outStr += ( "\n" + i + ")\t" + self.views[i] + ((i==self.curView)?("X"):("")) );
            }
        }else{
            outStr = "view is null" ;
        }
        return(outStr);
    }
    this.toString = toString;
    
    function CapToSize(n){
        if(self.views){
            return((n > self.views.length) ? (self.views.length) : ( (n < 0) ? (0) : (n) ));
        }
        return(0);
    }
    this.CapToSize = CapToSize;
    
    function CorrectCurrentView(){
        self.curView = self.CapToSize(self.curView);
    }
    this.CorrectCurrentView = CorrectCurrentView;
    
    function Clear(){
        self.views = new Array();
        self.CorrectCurrentView();
    }
    this.Clear = Clear;
    
    function ClipFrom(n){
        if (n < self.views.length && n >= 0)
        {
            if (n < (self.views.length - 1))
            {
                self.RemoveRange(n + 1, self.views.length - n - 1);
            }
        }
        self.CorrectCurrentView();    
    }
    this.ClipFrom = ClipFrom;
    
    function RemoveRange(s,l){
        if(self.views){
            try{
                self.views.splice(s,l);
            }catch(e){
                var newArray = new Array();
                var i = 0;
                var remStop = s + l;
                for(i = 0;i<s;i++){
                    newArray[i] = self.views[i];
                }
                var leftover = self.views.lengh - remStop;
                for(i = 0; i < leftover;i++){
                    newArray[s+i] = self.views[s+l+i];
                }
                self.views = newArray;
            }
            self.CorrectCurrentView();
        }
    }
    this.RemoveRange = RemoveRange;
    
    function Add(v)
    {
        if (v)
        {
            self.CorrectCurrentView();
            self.ClipFrom(self.curView);
            if (self.views.length >= self.maxHistory && self.curView == (self.views.length-1))
            {
                try{
                    self.views.shift();
                }catch(e){
                    var newArray = new Array();
                    for(var i = 1;i<self.views.length;i++){
                        newArray[i-1] = self.views[i];
                    }
                    self.views = newArray;
                }
            }
            this.views[this.views.length] = v; // may need to copy
            self.CorrectCurrentView();
            return (self.MoveTo(self.views.length - 1));
        }
        return (null);
    }
    this.Add = Add;
    
    function ReplaceCurrent(v){
        self.CorrectCurrentView();
        if(v){
            if(self.curView < self.views.length){
                if(self.curView >= 0){
                    self.views[self.curView] = v;
                }
            }else{
                self.Add(v);
            }
        }
    }
    this.ReplaceCurrent = ReplaceCurrent;
    
    function PeekAt(n)
    {
        if (n < self.views.length && n >= 0)
        {
            return (self.views[n]);
        }
        return (null);
    }
    this.PeekAt = PeekAt;
    
    function Peek(n)
    {
        self.CorrectCurrentView();
        return (self.PeekAt(self.curView + n));
    }
    this.Peek = Peek;

    function PeekNext()
    {
        return (self.Peek(1));
    }
    this.PeekNext = PeekNext;

    function PeekPrev()
    {
        return (self.Peek(-1));
    }
    this.PeekPrev = PeekPrev;
    
    function MoveTo(n)
    {
        // keep n within the range [0,this.views.Count)
        if (self.views.length > 0)
        {
            n = self.CapToSize(n);
            if (n >= 0 && n < self.views.length)
            {
                self.curView = n;
                self.CorrectCurrentView();
                return (self.GetCurrent());
            }
        }
        return (null);
    }
    this.MoveTo = MoveTo;
    
    function Move(n)
    {
        return (self.MoveTo(self.curView + n));
    }
    this.Move = Move;

    function MoveNext()
    {
        return (self.Move(1));
    }
    this.MoveNext = MoveNext;

    function MovePrev()
    {
        return (self.Move(-1));
    }
    this.MovePrev = MovePrev;
    
    function GetPosition(){
        return(self.curView);       
    }
    this.GetPosition = GetPosition;
    
    function GetCurrent(){
        if(self.views){
            self.CorrectCurrentView();
            return(self.views[self.curView]);
        }
        return(null);
    }
    this.GetCurrent = GetCurrent;
    
    function GetCount(){
        if(self.views){
            return(self.views.length);
        }
        return(0);
    }
    this.GetCount = GetCount;
}