var ships = [
   { src: "ship.gif", imgw: 30 * 2.5, imgh: 13 * 2.5 },
   { src: "rship.gif", imgw: 28 * 1.8, imgh: 22 * 1.8 },
   { src: "bship.gif", imgw: 34 * 1.3, imgh: 33 * 1.3 },
   { src: "spaceship.gif", imgw: 54.0 * 1.5, imgh: 43.0 * 1.5 }
];

var shipsrc, rshipsrc;
var r_flag = false;
var clip_imgw = 70;
//var clip_imgh = 70;

//number of ships
var no = 10;

var ie4up = (document.all) ? 1 : 0;
var ns6up = (document.getElementById && !document.all) ? 1 : 0;

var xp, yp;    //coordinate and position variables
var stx, sty;  //step variables
var rxp, ryp;    //coordinate and position variables
var rstx, rsty;  //step variables  

var i, doc_width = 800, doc_height = 600;
var op, rop; //opacity
var iw, ih, riw, rih; //sizes
var yclip;
var xclip;
var maxop = 1.8;

xp = new Array();
yp = new Array();
stx = new Array();
sty = new Array();

rxp = new Array();
ryp = new Array();
rstx = new Array();
rsty = new Array();

if (ns6up) {
    doc_width = self.innerWidth;
    doc_height = self.innerHeight;
} else if (ie4up) {
    doc_width = document.body.clientWidth;
    doc_height = document.body.clientHeight;
}

yclip = doc_height / 1.7;
xclip = doc_width - (clip_imgw / 2);


for (i = 0; i < no; ++i) {
    calc_lships(i);
    calc_rships(i);
    if (ns6up) {
        document.write("<div id=\"dot" + i + "\" style=\"overflow: hidden;opacity: " + op + ";POSITION: absolute; Z-INDEX: 100; VISIBILITY: visible; TOP: 15px; LEFT: 15px;\"><img width=" + iw + " height=" + ih + " id=\"im" + i + "\" src='" + shipsrc + "' border=\"0\"><\/div>");
        document.write("<div id=\"rdot" + i + "\" style=\"overflow: hidden;opacity: " + rop + ";POSITION: absolute; Z-INDEX: 100; VISIBILITY: visible; TOP: 15px; LEFT: 15px;\"><img width=" + riw + " height=" + rih + " id=\"rim" + i + "\" src='" + rshipsrc + "' border=\"0\"><\/div>");
    } else if (ie4up) {
    document.write("<div id=\"dot" + i + "\" style=\"filter:alpha(opacity=" + op + ");POSITION: absolute; Z-INDEX: 100; VISIBILITY: visible; TOP: 15px; LEFT: 15px;\"><img width=" + iw + " height=" + ih + " id=\"im" + i + "\" src='" + shipsrc + "' border=\"0\"><\/div>");
    document.write("<div id=\"rdot" + i + "\" style=\"filter:alpha(opacity=" + rop + ");POSITION: absolute; Z-INDEX: 100; VISIBILITY: visible; TOP: 15px; LEFT: 15px;\"><img width=" + riw + " height=" + rih + " id=\"rim" + i + "\" src='" + rshipsrc + "' border=\"0\"><\/div>");
    }
}

function calc_lships(i) {
    var lindex;
    lindex = Math.round(Math.random() * (ships.length - 1));
    xp[i] = Math.random() * (xclip);  // set position variables
    yp[i] = (yclip) + Math.random() * (doc_height - yclip - ships[lindex].imgh);
    stx[i] = Math.exp(3 * (yp[i] - yclip) / yclip) / 5;  //+ Math.random() / 10; // set step variables
    sty[i] = 0;     // set step variables
    op = (1 - (yclip) / yp[i]) * maxop;
    iw = ships[lindex].imgw * (1 - (yclip) / yp[i]);
    ih = ships[lindex].imgh * (1 - (yclip) / yp[i]);
    shipsrc = ships[lindex].src;
}

function calc_rships(i) {
    var rindex;
    rindex = Math.round(Math.random() * (ships.length - 1));
    rxp[i] = Math.random() * (xclip);  // set position variables
    ryp[i] = (yclip) + Math.random() * (doc_height - yclip - ships[rindex].imgh);
    rstx[i] = -1 * Math.exp(3 * (ryp[i] - yclip) / yclip) / 5; // set step variables
    rsty[i] = 0;     // set step variables
    rop = (1 - (yclip) / ryp[i]) * maxop;
    riw = ships[rindex].imgw * (1 - (yclip) / ryp[i]);
    rih = ships[rindex].imgh * (1 - (yclip) / ryp[i]);
    rshipsrc = ships[rindex].src;
}

function draw_ships() {  // IE and NS6 main animation function
    if (!r_flag) {
        r_flag = true;
        for (i = 0; i < no; ++i) {  // iterate for every dot
            rxp[i] += rstx[i];
            if (rxp[i] <= 0) {
                calc_rships(i);
                rxp[i] = (xclip);
                if (ns6up) {
                    document.getElementById("rdot" + i).style.opacity = rop;
                    document.getElementById("rim" + i).src = rshipsrc;
                    document.getElementById("rim" + i).width = riw;
                    document.getElementById("rim" + i).height = rih;
                }
                else if (ie4up) {
                    document.all["rdot" + i].style.filter = "alpha(opacity=\"" + rop + "\")";
                    document.all["rim" + i].src = rshipsrc;
                    document.all["rim" + i].width = riw;
                    document.all["rim" + i].height = rih;
                }
            }
            xp[i] += stx[i];
            if (xp[i] > xclip) {
                calc_lships(i);
                xp[i] = 0;
                if (ns6up) {
                    document.getElementById("dot" + i).style.opacity = op;
                    document.getElementById("im" + i).style.left = shipsrc;
                    document.getElementById("im" + i).width = iw;
                    document.getElementById("im" + i).height = ih;
                }
                else if (ie4up) {
                    document.all["dot" + i].style.filter = "alpha(opacity=\"" + op + "\")";
                    document.all["im" + i].src = shipsrc;
                    document.all["im" + i].width = iw;
                    document.all["im" + i].height = ih;
                }
            }
            //redraw
            if (ns6up) {
                document.getElementById("dot" + i).style.top = yp[i];
                document.getElementById("dot" + i).style.left = xp[i];
                document.getElementById("rdot" + i).style.top = ryp[i];
                document.getElementById("rdot" + i).style.left = rxp[i];
            }
            else if (ie4up) {
                document.all["dot" + i].style.pixelTop = yp[i];
                document.all["dot" + i].style.pixelLeft = xp[i];
                document.all["rdot" + i].style.pixelTop = ryp[i];
                document.all["rdot" + i].style.pixelLeft = rxp[i];
            }
            doc_width = ns6up ? window.innerWidth : document.body.clientWidth;
            doc_height = ns6up ? window.innerHeight : document.body.clientHeight;
        }
        r_flag = false;
    }
}

if (ie4up || ns6up) {
    setInterval(draw_ships, 30);
}

var starsrc = "star.gif";
var simgw = 5;
var simgh = 5;

var sno = 20;

var sxp, syp;    //coordinate and position variables
var stp;  //step variables

var syclip;
var sxclip;

var si;

sxp = new Array();
syp = new Array();
stp = new Array();

syclip = doc_height / 3;
sxclip = doc_width - 10;

for (si = 0; si < sno; ++si) {
    sxp[si] = Math.random() * (sxclip);  // set position variables
    syp[si] = Math.random() * (syclip);
    stp[si] = Math.random() * 30; 		// set step variables

    if (ie4up || ns6up) {
        document.write("<div id=\"star" + si + "\" style=\"POSITION: absolute; Z-INDEX: 200; VISIBILITY: visible; TOP: " + syp[si] + "px; LEFT: " + sxp[si] + "px;\"><img width=" + simgw + " height=" + simgh + " name=\"st" + si + "\" src='" + starsrc + "' border=\"0\"><\/div>");
    }
}

function starIE_NS6() {  // IE and NS6 main animation function

    if (ie4up) {
        document.all["sat"].style.pixelTop = 20;
        document.all["sat"].style.pixelLeft = doc_width - (doc_width / 6);
    }
    else if (ns6up) {
        document.getElementById("sat").style.top = 20;
        document.getElementById("sat").style.left = doc_width - (doc_width / 6);
    }

    for (si = 0; si < sno; ++si) {  // iterate for every dot
        stp[si] -= 1;
        if (stp[si] < 0) {
            sxp[si] = Math.random() * (sxclip);  // set position variables
            syp[si] = Math.random() * (syclip);
            stp[si] = Math.random() * 100; 		// set step variables
            doc_width = ns6up ? window.innerWidth : document.body.clientWidth;
            doc_height = ns6up ? window.innerHeight : document.body.clientHeight;
            if (ie4up) {
                document.all["star" + si].style.pixelTop = syp[si];
                document.all["star" + si].style.pixelLeft = sxp[si];
            }
            else if (ns6up) {
                document.getElementById("star" + si).style.top = syp[si];
                document.getElementById("star" + si).style.left = sxp[si];
            }
        }
    }
}

if (ie4up || ns6up) {
    setInterval(starIE_NS6, 400);
}


var trianglesHtml = [];
var MAX_DEPTH = 6;
var transparentColor = "transparent";

function renderTriangles(node) {
    node.innerHTML = trianglesHtml.join("");
    trianglesHtml = [];
}

function drawRightTriangle(p1, p2, color, above) {
    if (p1.y < p2.y) {
        if (above) {
            var result = "<div style=\"position:absolute;height:0px;left:" + Math.floor(p1.x) + "px;top:" + Math.ceil(p1.y) + "px;border-left-style:solid;border-top-style:solid;";
            result += "border-left-color:" + self.transparentColor + ";border-top-color:" + color;
            result += ";border-left-width:" + Math.ceil(p2.x - p1.x + 1) + "px;border-top-width:" + Math.ceil(p2.y - p1.y + 1) + "px;\"></div>";
            trianglesHtml.push(result);
        } else {
            var result = "<div style=\"position:absolute;height:0px;left:" + Math.ceil(p1.x) + "px;top:" + Math.floor(p1.y) + "px;border-right-style:solid;border-bottom-style:solid;";
            result += "border-right-color:" + self.transparentColor + ";border-bottom-color:" + color;
            result += ";border-right-width:" + Math.ceil(p2.x - p1.x + 1) + "px;border-bottom-width:" + Math.ceil(p2.y - p1.y + 1) + "px;\"></div>";
            trianglesHtml.push(result);
        }
    } else if (p1.y > p2.y) {
        if (above) {
            var result = "<div style=\"position:absolute;height:0px;left:" + Math.ceil(p1.x) + "px;top:" + Math.ceil(p2.y) + "px;border-right-style:solid;border-top-style:solid;";
            result += "border-right-color:" + self.transparentColor + ";border-top-color:" + color;
            result += ";border-right-width:" + Math.ceil(p2.x - p1.x + 1) + "px;border-top-width:" + Math.ceil(p1.y - p2.y + 1) + "px;\"></div>";
            trianglesHtml.push(result);
        } else {
            var result = "<div style=\"position:absolute;height:0px;left:" + Math.floor(p1.x) + "px;top:" + Math.floor(p2.y) + "px;border-left-style:solid;border-bottom-style:solid;";
            result += "border-left-color:" + self.transparentColor + ";border-bottom-color:" + color;
            result += ";border-left-width:" + Math.ceil(p2.x - p1.x + 1) + "px;border-bottom-width:" + Math.ceil(p1.y - p2.y + 1) + "px;\"></div>";
            trianglesHtml.push(result);
        }
    }
}

function drawFlatBottomTriangle(p1, p2, p3, color) {
    if (p1.x <= p2.x) {
        var depth = 0;
        var dy = (p3.y - p1.y) / (p3.x - p1.x);
        var dx = (p2.x - p1.x) / (p2.y - p1.y);

        while (p2.x - p1.x > 1) {
            var p4 = { x: p2.x, y: p1.y + (p2.x - p1.x) * dy };
            var p5 = { y: p4.y, x: p1.x + (p4.y - p1.y) * dx };

            drawRightTriangle(p4, p3, color, false);
            drawRightTriangle(p5, p2, color, true);

            if (++depth > MAX_DEPTH) {
                return;
            }

            p2 = p5;
            p3 = p4;
        }

        drawRightTriangle(p1, p3, color, false);
    } else if (p1.x >= p3.x) {
        var depth = 0;
        var dy = (p2.y - p1.y) / (p2.x - p1.x);
        var dx = (p3.x - p1.x) / (p3.y - p1.y);

        while (p1.x - p3.x > 1) {
            var p4 = { x: p3.x, y: p1.y + (p3.x - p1.x) * dy };
            var p5 = { y: p4.y, x: p1.x + (p4.y - p1.y) * dx };

            drawRightTriangle(p2, p4, color, false);
            drawRightTriangle(p3, p5, color, true);

            if (++depth > MAX_DEPTH) {
                return;
            }

            p2 = p4;
            p3 = p5;
        }

        drawRightTriangle(p2, p1, color, false);
    } else {
        drawRightTriangle(p2, p1, color, false);
        drawRightTriangle(p1, p3, color, false);
    }
}

function drawFlatTopTriangle(p1, p2, p3, color) {
    if (p1.x <= p2.x) {
        var depth = 0;
        var dy = (p3.y - p1.y) / (p3.x - p1.x);
        var dx = (p2.x - p1.x) / (p2.y - p1.y);

        while (p2.x - p1.x > 1) {
            var p4 = { x: p2.x, y: p1.y + (p2.x - p1.x) * dy };
            var p5 = { y: p4.y, x: p1.x + (p4.y - p1.y) * dx };

            drawRightTriangle(p4, p3, color, true);
            drawRightTriangle(p5, p2, color, false);

            if (++depth > MAX_DEPTH) {
                return;
            }

            p2 = p5;
            p3 = p4;
        }

        drawRightTriangle(p1, p3, color, true);
    } else if (p1.x >= p3.x) {
        var depth = 0;
        var dy = (p2.y - p1.y) / (p2.x - p1.x);
        var dx = (p3.x - p1.x) / (p3.y - p1.y);

        while (p1.x - p3.x > 1) {
            var p4 = { x: p3.x, y: p1.y + (p3.x - p1.x) * dy };
            var p5 = { y: p4.y, x: p1.x + (p4.y - p1.y) * dx };

            drawRightTriangle(p2, p4, color, true);
            drawRightTriangle(p3, p5, color, false);

            if (++depth > MAX_DEPTH) {
                return;
            }

            p2 = p4;
            p3 = p5;
        }

        drawRightTriangle(p2, p1, color, true);
    } else {
        drawRightTriangle(p2, p1, color, true);
        drawRightTriangle(p1, p3, color, true);
    }
}

function compareY(p1, p2) {
    return p1.y - p2.y;
}

function drawTriangle(points, color) {
    points.sort(compareY);
    var p1 = points[0];
    var p2 = points[1];
    var p3 = points[2];

    if (p2.y - p1.y < 0) {
        if (p1.x > p2.x) {
            drawFlatTopTriangle(p3, p2, p1, color);
        } else {
            drawFlatTopTriangle(p3, p1, p2, color);
        }
    } else if (p3.y - p2.y < 0) {
        if (p2.x > p3.x) {
            drawFlatBottomTriangle(p1, p3, p2, color);
        } else {
            drawFlatBottomTriangle(p1, p2, p3, color);
        }
    } else {
        var p4 = { y: p2.y, x: p1.x + (p2.y - p1.y) * ((p3.x - p1.x) / (p3.y - p1.y)) };

        if (p2.x > p4.x) {
            drawFlatBottomTriangle(p1, p4, p2, color);
            drawFlatTopTriangle(p3, p4, p2, color);
        } else {
            drawFlatBottomTriangle(p1, p2, p4, color);
            drawFlatTopTriangle(p3, p2, p4, color);
        }
    }
}

function drawRandomTriangle(xMin, xRange, yMin, yRange) {
    var p1 = { x: xMin + Math.random() * xRange, y: yMin + Math.random() * yRange };
    var p2 = { x: xMin + Math.random() * xRange, y: yMin + Math.random() * yRange };
    var p3 = { x: xMin + Math.random() * xRange, y: yMin + Math.random() * yRange };

    var color = "rgb(" +
                  Math.floor(Math.random() * 256) + "," +
                  Math.floor(Math.random() * 256) + "," +
                  Math.floor(Math.random() * 256) + ")";

    drawTriangle([p1, p2, p3], color);
}

function initializeNormals(obj) {
    for (var i = 0, poly; poly = obj.polys[i]; ++i) {
        poly.norm = Vector.crossProduct(Vector.subtract(obj.points[poly.points[1]], obj.points[poly.points[0]]),
                                        Vector.subtract(obj.points[poly.points[2]], obj.points[poly.points[0]])).normalize()
    }
}

var view = {
    pos: new Vector(),
    dir: new Vector(0, 0, -1)
};

var light = {
    dir: Vector.rotate(Vector.rotate(new Vector(0, 0, -1), 0.2, "x"), 0.3, "y"),
    intensity: 0.85,
    ambient: 0.15
};

var points = [];
var polys = [];

var star_color = new Vector(0xff, 0xcc, 0x66);
var hull_color = new Vector(0xcc, 0x66, 0x00);
var back_color = new Vector(0xff, 0xff, 0xcc);

var star = {
    pos: new Vector(-200, -300, -500),
    orientation: new Quat(),

    points: [
        new Vector(-30, 30, 30),
        new Vector(30, 30, 30),
        new Vector(30, -30, 30),
        new Vector(-30, -30, 30),
        new Vector(-30, 30, -30),
        new Vector(30, 30, -30),
        new Vector(30, -30, -30),
        new Vector(-30, -30, -30),

        new Vector(0, 50, 0),
        new Vector(150, 0, 0),
        new Vector(0, -50, 0),
        new Vector(-150, 0, 0),
        new Vector(0, 0, 150),
        new Vector(0, 0, -150)
      ],

    polys: [
        { points: [0, 12, 1], color: hull_color },
        { points: [1, 12, 2], color: star_color },
        { points: [2, 12, 3], color: star_color },
        { points: [3, 12, 0], color: star_color },

        { points: [4, 13, 7], color: star_color },
        { points: [7, 13, 6], color: star_color },
        { points: [6, 13, 5], color: star_color },
        { points: [5, 13, 4], color: hull_color },

        { points: [0, 8, 4], color: hull_color },
        { points: [4, 8, 5], color: star_color },
        { points: [5, 8, 1], color: hull_color },
        { points: [1, 8, 0], color: star_color },

        { points: [2, 10, 6], color: hull_color },
        { points: [6, 10, 7], color: star_color },
        { points: [7, 10, 3], color: hull_color },
        { points: [3, 10, 2], color: star_color },

        { points: [1, 9, 5], color: star_color },
        { points: [5, 9, 6], color: star_color },
        { points: [6, 9, 2], color: star_color },
        { points: [2, 9, 1], color: star_color },

        { points: [3, 11, 7], color: star_color },
        { points: [7, 11, 4], color: star_color },
        { points: [4, 11, 0], color: star_color },
        { points: [0, 11, 3], color: star_color }
      ]
};

initializeNormals(star);

function addObjectPolys(obj) {
    var pointsOffset = self.points.length;

    for (var i = 0, point; point = obj.points[i]; ++i) {
        var newPoint = obj.orientation.translateVector(point).add(obj.pos);

        self.points.push(newPoint);
    }

    for (var i = 0, poly; poly = obj.polys[i]; ++i) {
        var norm = obj.orientation.translateVector(poly.norm);

        var p1 = pointsOffset + poly.points[0];
        var p2 = pointsOffset + poly.points[1];
        var p3 = pointsOffset + poly.points[2];

        if (Vector.dotProduct(norm, Vector.subtract(self.points[p1], view.pos)) >= 0) {
            continue;
        }

        var color = Vector.scale(poly.color, light.ambient + Math.max(0, -light.intensity * Vector.dotProduct(norm, light.dir)));

        var z = self.points[p1].z +
                self.points[p2].z +
                self.points[p3].z;

        self.polys.push({
            points: [p1, p2, p3],
            color: color,
            z: z
        });
    }

    for (var i = pointsOffset, point; point = self.points[i]; ++i) {
        point.x /= -point.z * 0.002;
        point.y /= -point.z * 0.002;
        point.x += 200;
        point.y = 200 - point.y;
    }
}

function compareZ(p1, p2) {
    return p1.z - p2.z;
}

function drawPolys(node) {
    self.polys.sort(compareZ);

    for (var i = 0, poly; poly = self.polys[i]; ++i) {
        drawTriangle([self.points[poly.points[0]], self.points[poly.points[1]], self.points[poly.points[2]]],
                     "rgb(" + Math.floor(poly.color.x) + "," + Math.floor(poly.color.y) + "," + Math.floor(poly.color.z) + ")");
    }

    self.polys = [];
    self.points = [];
    renderTriangles(node);
}

var rotateX = 0;
var rotateY = 0;
var rotateZ = 0;

var xUnit = new Vector(1, 0, 0);
var yUnit = new Vector(0, 1, 0);
var zUnit = new Vector(0, 0, 1);

var manuallyRotated = false;
var ROTATE_SPEED = 0.05;
var TARGET_FPS = 20;
var cx = 3000, cy = 1000, cz = 1000;
var x, y, z;
var op = 0.0;
var beta = -1 * Math.PI;
var delta = -1 * Math.PI;

function draw() {
    addObjectPolys(star);
    drawPolys(container);
}

function animate() {
    if (!manuallyRotated) {
        star.orientation = Quat.rotate(star.orientation, yUnit, ROTATE_SPEED);
        x = (2000) + cx * Math.cos(beta) * Math.cos(delta);
        y = (-500) + cy * Math.cos(beta) * Math.sin(delta);
        z = (-3000) + cz * Math.sin(beta);
        star.pos = new Vector(x, y, z);
        //cz += -10; cx += 20;
        delta += 0.005;
        beta += 0.007;
        if (delta >= Math.PI) delta = -1 * Math.PI;
        if (beta >= Math.PI) beta = -1 * Math.PI;
        op = 500 / Math.abs(z);
        container.style.opacity = op;
    } else {
        if (rotateX) {
            star.orientation = Quat.rotate(star.orientation, xUnit, rotateX);
        }

        if (rotateY) {
            star.orientation = Quat.rotate(star.orientation, yUnit, rotateY);
        }

        if (rotateZ) {
            star.orientation = Quat.rotate(star.orientation, zUnit, rotateZ);
        }
    }

    draw();
}

function load() {
    self.container = document.getElementById("container");
    star.orientation = Quat.rotate(star.orientation, xUnit, -.5);
    star.orientation = Quat.rotate(star.orientation, yUnit, -.5);
    setInterval(animate, 1000 / TARGET_FPS);
}

function keydown(event) {
    var key = String.fromCharCode(event.keyCode || event.which);

    switch (key) {
        case "A":
            rotateY = -ROTATE_SPEED;
            manuallyRotated = true;
            break;
        case "D":
            rotateY = ROTATE_SPEED;
            manuallyRotated = true;
            break;
        case "W":
            rotateX = -ROTATE_SPEED;
            manuallyRotated = true;
            break;
        case "S":
            rotateX = ROTATE_SPEED;
            manuallyRotated = true;
            break;
        case "Q":
            rotateZ = -ROTATE_SPEED;
            manuallyRotated = true;
            break;
        case "E":
            rotateZ = ROTATE_SPEED;
            manuallyRotated = true;
            break;
        default:
            return true;
    }

    return false;
}

function keyup(event) {
    var key = String.fromCharCode(event.keyCode || event.which);

    switch (key) {
        case "A":
        case "D":
            rotateY = 0;
            break;
        case "W":
        case "S":
            rotateX = 0;
            break;
        case "Q":
        case "E":
            rotateZ = 0;
            break;
        default:
            return true;
    }

    return false;
}