
// require_once 'lib/prototype.js';
// require_once 'classes/ProjectileLab.js';
// require_once 'classes/Math.js';

ProjectileLab.Question = {
    xmin: 10,
    xmax: ProjectileLab.width / ProjectileLab.px_per_meter,
    ymin: 5,
    ymax: ProjectileLab.height / ProjectileLab.px_per_meter - 10,
    amin: 10,
    amax: 80
}

ProjectileLab.Question.Range = Class.create();
ProjectileLab.Question.Range.generate = function () {
    var bounds = ProjectileLab.Question;
    
    var height = Math.randomInt(bounds.ymin, bounds.ymax);
    var angle  = Math.randomInt(bounds.amin, bounds.amax);
    var range  = Math.randomInt(bounds.xmin, bounds.xmax); // not final
    var rad = angle * Math.RpD;
    
    var num = -4.9 * range * range;
    var den = Math.pow(Math.cos(rad), 2) * (- height - range * Math.tan(rad));
    var speed = Math.round(Math.sqrt(num / den));
    
    return new ProjectileLab.Question.Range(speed, angle, height);
}
ProjectileLab.Question.Range.prototype = {
    
    name: "Range",
    
    speed: 0,
    angle: 0, // in degrees
    height: 0,  // distance traveled downwards (-d_y)
    
    answerUnit: 'm',
    
    initialize: function (speed, angle, height) {
        this.speed = speed;
        this.angle = angle;
        this.height = height; // NOT d_y
    },
    
    // returns range
    getAnswer: function () {
        var rad = this.angle * Math.RpD;
        var a = -4.9;
        var b = this.speed * Math.sin(rad);
        // technically speaking, the equations involved use d_y, which 
        // actually is negative. At first glance, it makes more sense to
        // deal in terms of initial height rather than distance traveled
        // in y (a negative vector quantity). We've adopted a defense in
        // depth measure and decided to make c positive under all circumstances,
        // and ignore situations where the projectile is shot from underground.
        var c = Math.abs(this.height); // = -d_y
        var t = Math.quadratic(a, b, c); // time
        return this.speed * Math.cos(rad) * t;
    },
    
    getQuestion: function () {
        if (this.angle == 0) {
            return  "A projectile is fired horizontally from a ledge " +
                    this.height + " m high at " + this.speed +
                    " m/s. How far away (in meters) from the foot of the ledge" +
                    " does the projectile land?";
        } else if (this.height == 0) {
            return  "A projectile is fired at a velocity of " + this.speed +
                    " m/s " + this.angle + " degrees from the horizontal on a" +
                    " level field. How far away (in meters) does it land?"
        } else {
            return  "A projectile is fired from a ledge " + this.height +
                    " m high at " + this.speed + " m/s " +
                    this.angle + " degrees from the horizontal. How far away (in meters)" +
                    " from the foot of the ledge does the projectile land?"
        }
    },
    
    render: function (id, answer) {
        points = ProjectileLab.plotProjectile(this.speed, this.angle,
            this.height, this.getAnswer());
        
        // render answer target
        var answer_coordinates = Array(answer, 0);
        var target = ProjectileLab.generateTarget(answer_coordinates);
        $(id).appendChild(target);
        
        // draw graph
        ProjectileLab.animateProjectile(id, points);
    }
    
}

ProjectileLab.Question.NoAngleRange = Class.create();
ProjectileLab.Question.NoAngleRange.generate = function () {
    return new ProjectileLab.Question.NoAngleRange(
        Math.round(Math.random() * 30 + 5),
        Math.round(Math.random() * 20 + 20)
    );
}
Object.extend(ProjectileLab.Question.NoAngleRange.prototype, ProjectileLab.Question.Range.prototype);
Object.extend(ProjectileLab.Question.NoAngleRange.prototype, {
    
    name: "Falling Range",
    angle: 0, // constant
    
    initialize: function (speed, height) {
        this.speed = speed;
        this.height = height;
    }
    
});

ProjectileLab.Question.NoHeightRange = Class.create();
ProjectileLab.Question.NoHeightRange.generate = function () {
    return new ProjectileLab.Question.NoHeightRange(
        Math.round(Math.random() * 30 + 10),
        Math.round(Math.random() * 80 + 5)
    );
}
Object.extend(ProjectileLab.Question.NoHeightRange.prototype, ProjectileLab.Question.Range.prototype);
Object.extend(ProjectileLab.Question.NoHeightRange.prototype, {
    
    name: "Level Range",
    height: 0, // constant
    
    initialize: function (speed, angle) {
        this.speed = speed;
        this.angle = angle;
    }
    
});

ProjectileLab.Question.Height = Class.create();
ProjectileLab.Question.Height.generate = function () {
    var question = new ProjectileLab.Question.Height(
        Math.round(Math.random() * 10 + 30),
        Math.round(Math.random() * 40 + 10),
        Math.round(Math.random() * 50 + 20)
    );
    if (question.getAnswer() > 0) return question;
    else return ProjectileLab.Question.Height.generate();
}
ProjectileLab.Question.Height.prototype = {
    
    name: "Height",
    speed: 0,
    angle: 0, // in degrees
    distanceToWall: 0, // d_x
    
    answerUnit: 'm',
    
    initialize: function (speed, angle, distanceToWall) {
        this.speed = speed;
        this.angle = angle;
        this.distanceToWall = distanceToWall;
    },
    
    // returns height
    getAnswer: function () {
        var rad = this.angle * Math.RpD;
        var t = this.distanceToWall / this.speed / Math.cos(rad);
        return this.speed * Math.sin(rad) * t - 4.9 * Math.pow(t, 2);
    },
    
    getQuestion: function() {
        return  "A projectile is fired at " + this.speed + " m/s " +
                this.angle + " degrees from the horizontal. There is a wall " +
                this.distanceToWall + " m away. How high up the wall (in meters) will " +
                "the projectile strike?";
    },
    
    render: function (id, answer) {
        var width = ProjectileLab.width / ProjectileLab.px_per_meter;
        points = ProjectileLab.plotProjectile(this.speed, this.angle,
            0, this.distanceToWall, width - this.distanceToWall);
        
        // render answer target
        var answer_coordinates = Array(width, answer);
        var target = ProjectileLab.generateTarget(answer_coordinates);
        $(id).appendChild(target);
        
        // draw graph
        ProjectileLab.animateProjectile(id, points);
    }
    
}

ProjectileLab.Question.Speed = Class.create();
ProjectileLab.Question.Speed.generate = function() {
    var question = new ProjectileLab.Question.Speed(
        Math.round(Math.random() * 30 + 30),
        Math.round(Math.random() * 30 + 10),
        Math.round(Math.random() * 40 + 10)
    );
    var ans = question.getAnswer();
    if (ans > 0 && ans < 100) return question;
    else return ProjectileLab.Question.Speed.generate();
}
ProjectileLab.Question.Speed.prototype = {
    
    name: "Speed",
    distanceToWall: 0,
    height: 0,
    angle: 0,
    
    answerUnit: 'm/s',
    
    initialize: function (distanceToWall, height, angle) {
        this.distanceToWall = distanceToWall,
        this.height = height;
        this.angle = angle;
    },
    
    // returns speed
    getAnswer: function () {
        var rad = this.angle * Math.RpD;
        var num = -4.9 * Math.pow(this.distanceToWall, 2);
        var den = Math.pow(Math.cos(rad), 2) * (this.height - Math.tan(rad) * this.distanceToWall);
        return Math.sqrt(num / den);
    },
    
    getQuestion: function () {
        return  "You would like to hit a point " + this.height + " m up on " +
                "a wall that is " + this.distanceToWall + " m away. If you " +
                "are firing the projectile from ground-level at an angle of " +
                this.angle + " degrees, at what speed (in m/s) must it be fired to " +
                "hit your target?";
    },
    
    render: function(id, answer) {
        var width = ProjectileLab.width / ProjectileLab.px_per_meter;
        points = ProjectileLab.plotProjectile(answer, this.angle,
            0, this.distanceToWall, width - this.distanceToWall);
        
        // render answer target
        var answer_coordinates = Array(width, this.height);
        var target = ProjectileLab.generateTarget(answer_coordinates);
        $(id).appendChild(target);
        
        // draw graph
        ProjectileLab.animateProjectile(id, points);
    }
    
}

ProjectileLab.Question.Tank = Class.create();
ProjectileLab.Question.Tank.generate = function() {
    return new ProjectileLab.Question.Tank(
        Math.round(Math.random() * 40 + 60),
        Math.round(Math.random() * 55 + 30),
        Math.round(Math.random() * 8 + 2)
    );
}
ProjectileLab.Question.Tank.prototype = {
    
    name: "Tank",
    answers: 2,
    answerLabels: ['Speed', 'Range'],
    answerUnit: ['m/s', 'm'],
    
    distanceToTank: 0,
    angle: 0,
    speedOfTank: 0,
    
    initialize: function (distanceToTank, angle, speedOfTank) {
        this.distanceToTank = distanceToTank,
        this.angle = angle;
        this.speedOfTank = speedOfTank;
    },
    
    // returns Array(speed, range)
    getAnswer: function () {
        var rad = this.angle * Math.RpD;
        var a = Math.sin(rad) * Math.cos(rad) / 4.9;
        var b = this.speedOfTank * Math.sin(rad) / 4.9;
        var c = - this.distanceToTank;
        var speed = Math.quadratic(a, b, c, true);
        var t = speed * Math.sin(rad) / 4.9;
        var range = this.distanceToTank - t * this.speedOfTank;
        return Array(speed, range);
    },
    
    getQuestion: function () {
        return  "A tank that is " + this.distanceToTank + " m away is " +
                "approaching you at a speed of " + this.speedOfTank + " m/s." +
                "Your cannon currently is set at a " + this.angle + " degree " +
                "angle: at what speed (in m/s) must you fire the cannon-ball to hit the " +
                "tank? How far away (in meters) will the tank be when you hit it? " +
                "Separate your answers with a comma.";
    },
    
    render: function (id, answer) {
        
        var real_answer = this.getAnswer();
        points = ProjectileLab.plotProjectile(answer[0], this.angle,
            0, Number.Infinity);
        
        // render target
        var target_coordinates = Array(answer[1], 0);
        var target = ProjectileLab.generateTarget(target_coordinates);
        $(id).appendChild(target);
        
        // render tank
        var tank_coordinates = Array(this.distanceToTank, 0);
        var tank = ProjectileLab.generateTarget(tank_coordinates);
        tank.className = '';
        tank.id = 'tank';
        $(id).appendChild(tank);
        
        // draw graph
        ProjectileLab.animateProjectile(id, points, this.speedOfTank,
            this.distanceToTank);
    }
    
}
