Sky = function () {


    this.draw = function () {
            var times = weatherApp.times;
            var opacity = 1.0;
            var now = times.now.getTime();
            var min30 = 1000*30*60;
            var srLess30 = times.sunRise.getTime() - min30;
            var ssPlus30 = times.sunSet.getTime() + min30;
            // alert('now '+times.now.toString()+' srLess30 '+new Date(srLess30).toString());
            if (now < srLess30){
            } else
            if (now > ssPlus30){
            } else
            if (now < times.sunRise.getTime()){
              var ms = times.sunRise.getTime() - now;
              opacity = ms/min30;
            } else
            if (now > times.sunSet.getTime()){
              var ms = now - times.sunSet.getTime();
              opacity = ms/min30;
            } else {
             opacity = 0;
            }
            if (opacity > 0.8) opacity = 0.8;
            weatherApp.opacity = opacity;
            var rgb = weatherApp.options.rgb;
            Timeline.canvas.style.background.color = "rgba(10,10,30," + opacity + ")";
            Timeline.canvas.style.background.image = "-webkit-linear-gradient(top,rgba(0,0,0,"+opacity+"), rgba("+rgb.r+','+rgb.g+','+rgb.b+','+opacity+"))";
            Timeline.canvas.style.background.image  = "-moz-linear-gradient(top,rgba(0,0,0,"+opacity+"), rgba("+rgb.r+','+rgb.g+','+rgb.b+','+opacity+"))";
            Timeline.canvas.style.background.image  = "-o-linear-gradient(top, rgba(0,0,0,"+opacity+"), rgba("+rgb.r+','+rgb.g+','+rgb.b+','+opacity+"))";
            Timeline.canvas.style.background.image  = "-ms-linear-gradient(top, rgba(0,0,0,"+opacity+"), rgba("+rgb.r+','+rgb.g+','+rgb.b+','+opacity+"))";
            //Timeline.canvas.style.background.image  = "linear-gradient(top, black, blue)";
            Timeline.canvas.style.background  = "linear-gradient(top, rgba(0,0,0,"+opacity+"), rgba("+rgb.r+','+rgb.g+','+rgb.b+','+opacity+"))";
            Timeline.canvas.style.background = "-webkit-gradient(linear, left top, left bottom, from(rgba(0,0,0,"+opacity+")),to(rgba("+rgb.r+','+rgb.g+','+rgb.b+','+opacity+")))";

    },


    this.nextFrame = function () {
        this.draw();
    }

    this.nextFrame();

    return this;

}

Cloud = function (type) {

    var minY = weatherApp.options.cloudMinY,
        maxY = weatherApp.options.cloudMaxY,
        x = Math.random() * Timeline.canvas.width,
        y = Tools.randomRange(minY, maxY),
        width = 56,
        height = 36,
        wind = (weatherApp.options.wind == '')?Wind.value:weatherApp.options.wind/4,
        velX = wind + Tools.randomRange(-2, 2),
        img = undefined;

    if (velX < 1 && velX > -1) velX = wind;

    init = function (type) {
        img = new Image();
        img.src = "images/cloud"+type+".png";
    },

    this.draw = function () {
        //Timeline.context.fillStyle = "#fff";
        Timeline.context.drawImage(img, x, y);
    },

    this.move = function (callback) {
        x += (velX);
        if (x > Timeline.canvas.width) x = 0 - width;
        if (x < 0 - width) x = Timeline.canvas.width
    }

    this.nextFrame = function () {
        this.draw();
        this.move();
    }

    init(type);
    this.nextFrame();

    return this;

}

Moon = function () {

    var x = Timeline.canvas.width,
        y = Timeline.canvas.height,
        endY = weatherApp.options.moonEndY,
        endX = 0,
        radius = 40,
        img = undefined;
        velY = -3;
        /*
        img = new Image();
        img.src = "images/moon"+weatherApp.moonPhase+".png";
        */


    this.init = function () {


    }

    this.calculateOpacity = function () {

        var times = weatherApp.times;
        var ret = 100;

        if (times.sunRise > times.now) ret = 100;
        else if (times.highDate > times.now) {
            ret = Math.sqrt((times.timeTilHighest * times.timeTilHighest) / (times.sunRise * times.sunRiseLength)) * 50;
        }
        else if (times.sunSet > times.now) {
            ret = Math.sqrt(((0 - times.timeTilHighest) * (0 - times.timeTilHighest)) / (times.sunRiseLength * times.sunRiseLength)) * 50;
        }
        else if (times.lowDate > times.now) ret = 100;
        else ret = 100;

        endX = -1;
        if (times.now.getTime() < times.sunRise.getTime()){ // morning
          var yesterdaySunSet = times.sunSet.getTime()-(24*60*60*1000);
          var nightTime = times.sunRise.getTime() - yesterdaySunSet; // assume it's the day before
          var moonTime = times.now.getTime()-yesterdaySunSet;
          endX = 0;
        }
        if (times.now.getTime() > times.sunSet.getTime()){ // evening
          var tomorrowSunRise = times.sunRise.getTime()+(24*60*60*1000);
          var nightTime = tomorrowSunRise - times.now.getTime();
          var moonTime = times.now.getTime() - times.sunSet.getTime();
          endX = 0;
        }

        if (endX == 0) {
          var portion = moonTime/nightTime;
          endX = Timeline.canvas.width-(portion*Timeline.canvas.width);
        }
        return ret / 100;
    }

    this.move = function () {
      if (y > endY) y+= velY;
      if (x > endX) x+= velX;

    }

    this.draw = function () {
        if (endX <= 0) return;
        //x = Timeline.canvas.width - radius * 2 - 50;

        opacity = this.calculateOpacity();
        if (opacity > 0.8) opacity = 0.8;

        /*
        Timeline.context.fillStyle = "rgba(255, 255, 255," + opacity + ")";
        Timeline.context.beginPath();
        Timeline.context.arc(x, y, radius, 0, Math.PI * 2, true); // Outer circle
        Timeline.context.fill();
        if ($('#moon') != '') {
          if ($i('moon').innerHTML == '') {
            $i('moon').style.display = '';
            $i('moon').innerHTML=moonHTML(new Date(weatherApp.time),30,weatherApp.coords.latitude,'/images/trans.gif','/images/white.gif');
          }
          $i('moon').style.left = Math.round(Timeline.canvas.offsetLeft+x)+'px';
          $i('moon').style.top = Math.round(Timeline.canvas.offsetTop+y)+'px';
          $i('moon').style.opacity = opacity;
        } else {
          img.opacity = opacity;
          Timeline.context.drawImage(img, x, y);
        }
        */
        moonCanvas(new Date(),x,y,radius,weatherApp.coords.latitude,opacity);
        this.move();
    }
    this.calculateOpacity();
    endY = 0;
    var timetaken = Timeline.canvas.height/velY;
    velX = (Timeline.canvas.width-endX)/timetaken;
}

Parallax = function () {
    var imgs = [{
        src: 'images/parallax_1.png',
        width: 1255,
        height: 140,
    },
    {
        src: 'images/parallax_2.png',
        width: 895,
        height: 141,
    },
    {
        src: 'images/parallax_3.png',
        width: 637,
        height: 177,
    }];

    var distance = 5;

    var xShift = 0;

    $(document).bind("mousemove", function (e) {
        xShift = ((e.screenX / window.innerWidth) * distance) - distance / 2;

    })

    this.init = function () {
        for (i in imgs) {
            var img = imgs[i];
            var image = new Image();
            image.src = img.src;
            imgs[i].image = image;
            image.onload = function () {
                Timeline.context.drawImage(image, img.x, img.y);
            }
        }
    }

    this.draw = function () {

        for (i in imgs) {
            var img = imgs[i];
            img.x = parseInt((Timeline.canvas.width - img.width) / 2);
            img.y = parseInt(Timeline.canvas.height - img.height) - 37,


            image = img.image;
            var xs = (xShift * (12 - 4 * i)) - xShift
            var x = img.x + xs;
            var y = img.y;
            Timeline.context.drawImage(image, x, y);
        }
    }

    var t = this;
    $(document).bind("timeline.frame", function () {
        t.draw();
    })
    this.init();
    this.draw();

    return this;
}

// requires RainDrop.js, Wind.js
Rain = function (count) {

    var drops = [],
        dropCount = count;

    this.create = function () {
        for (var i = 0; i < dropCount; i++) {
            var drop = new RainDrop();
            drops.push(drop);
        }

        var t = this;
    }
    this.create();

    this.rain = function () {
        for (var i = 0; i < drops.length; i++) {
            drops[i].nextFrame();
        }
    }
    this.rain();
    return this;
}

RainDrop = function () {

    var x = Math.random() * Timeline.canvas.width,
        y = Math.random() * Timeline.canvas.height,
        zIndex = Tools.randomRange(1, 11),
        // 1 at front 11 at back
        opacity = Math.random() / zIndex,

        width = (Math.random() * 2 + 1) * (11 / zIndex),
        height = width * 2,
        color = "rgba(100,100,255," + opacity + ")",
        xVel = Tools.randomRange(Wind.value - 1, Wind.value + 1) * (11 / zIndex),
        yVel = Math.random() * 10 + 2 * (11 / zIndex);


    init = function (type) {
       /*
        img = new Image();
        img.src = "images/raindrop.png";
        img.width = width;
       */
        reset();

    },

    this.setColor = function (c) {
        color = c;
    },

    this.getX = function () {
        return x;
    }

    this.getY = function () {
        return y;
    }

    this.getWidth = function () {
        if (width === 0) width = 2;
        return width;
    }

    this.getHeight = function () {
        return height;
    }

    this.getColor = function () {
        return color;
    }

    this.getOpacity = function () {
        return opacity;
    }

    this.nextFrame = function () {
        this.draw();
        this.move();
    }

    xVel = 0;

/*
        $(document).bind("mousemove",function(e) {
                var scale = 8;
                weatherApp.mouse = e;
                xVel = ((e.screenX / window.innerWidth) * scale) - scale / 2;
        })
        */


    reset = function (type) {
        x = Math.random() * Timeline.canvas.width;
        y = Math.random() * Timeline.canvas.height;
        zIndex = Tools.randomRange(1, 11); // 1 at front 11 at back
        opacity = Math.random() / zIndex;
        var v = 10;
        if (typeof type != 'undefined') v = 4;
        yVel = Math.random() * v + 2 * (11 / zIndex);
        width = 0.5 * (Math.random() * 2 + 1) * (11 / zIndex);
        height = width * 2;

    },

    this.draw = function () {
        if (width === 0) width = 2;

        Timeline.context.fillStyle = color;
        //Timeline.context.fillRect(x, y, width, height);

        Timeline.context.fillStyle = "rgba(0, 0, 255," + opacity + ")";
        Timeline.context.beginPath();
        Timeline.context.arc(x, y, width/2, 0, Math.PI * 2, true); // Outer circle
        Timeline.context.fill();

    },

    this.move = function (callback) {

        x += xVel;
        y += yVel;
        if (x > Timeline.canvas.width || y > Timeline.canvas.height) {

            x = Math.random() * Timeline.canvas.width;
            y = 0;
            zIndex = Tools.randomRange(1, 11); // 1 at front 11 at back
            opacity = Math.random() / zIndex;
            yVel = Math.random() * 10 + 2 * (11 / zIndex);
            width = (Math.random() * 2 + 1) * (11 / zIndex);
            height = width * 2;

        } else {}

        x = parseInt(x);
        y = parseInt(y);

        if (y === 0 && x < 100) {
            x = 0;
            y = parseInt(Math.random() * Timeline.canvas.height)
        }

        if (y === 0 && Timeline.canvas.width - x < 100) {
            x = Timeline.canvas.width;
            y = parseInt(Math.random() * Timeline.canvas.height)
        }
    }
    init(function () {});

    return this;

}








// requires RainDrop.js, Wind.js
Snow = function (count) {

    var drops = [],
        dropCount = count;



    this.create = function () {
        for (var i = 0; i < dropCount; i++) {
            var drop = new RainDrop('snow');

            drop.draw = function () {
                Timeline.context.fillStyle = "rgba(255,255,255," + this.getOpacity() + ")";
                Timeline.context.font = (this.getWidth() * 2) + "pt Helvetica";
                //Timeline.context.fillRect(this.getX(),this.getY(),this.getWidth(),this.getHeight());
                Timeline.context.fillText("*", this.getX(), this.getY());




            }
            drops.push(drop);
        }

        var t = this;
    }
    this.create();

    this.snow = function () {
        for (var i = 0; i < drops.length; i++) {
            drops[i].nextFrame();
        }
    }
    this.snow();
    return this;
}

Star = function (count) {

    var minY = weatherApp.options.cloudMinY,
        maxY = weatherApp.options.cloudMaxY,
        stars = [],
        starCount = count;



    this.create = function () {
        for (var i = 0; i < starCount; i++) {
            var star = new this.Particle();
            var zIndex = Timeline.canvas.zIndex -1;
            star.draw = function () {
                Timeline.context.fillStyle = "rgba(255,255,0," + Tools.randomRange(0, 1) + ")";
                Timeline.context.font = (this.width) + "pt Helvetica";
                Timeline.context.fillText("*", this.x, this.y);
                Timeline.context.zIndex = zIndex;
            }
            stars.push(star);
        }

        var t = this;
    }

    this.Particle = function () {

        this.x = Math.random() * Timeline.canvas.width;
        this.y = Math.random() * maxY;
        var z = Tools.randomRange(-10, 10);

        this.scale = 250 / (250 + z);
        this.shrink = 0.96;
        this.shrink = 0;
        this.colour = "yellow";
        this.width = Math.round(this.scale * 14);

    };

    this.create();

    this.star = function () {
        for (var i = 0; i < stars.length; i++) {
            stars[i].draw();
        }
    }
    this.star();
    return this;
}

function createDateHHMM(HHMM) {
    var now = new Date(Date(weatherApp.time));
    var time = HHMM.split(':');
    now.setHours(1 * time[0], 1 * time[1]);
    return now.toString();
}

function createDate(date) { // YYYY-MM-DD HH:MM
    date = date.replace(/-/g,' ');
    date = date.replace(/:/g,' ');
    var parts = date.split(' ');

    var now = new Date(parts[0], parts[1]-1, parts[2], parts[3], parts[4]);
    return now.toString();
}

Sun = function () {

    var x = Timeline.canvas.width,
        y = Timeline.canvas.height,
        endY = 0,
        endX = 0,
        radius = 20,
        velX = -3,
        velY = -3;


    log("Sunrise: " + weatherApp.data.astronomy.sunrise);
    log("Sunset: " + weatherApp.data.astronomy.sunset);


    calculateEndPosition = function () {
        var times = weatherApp.times;
        var ret = 100;

        if (times.sunRise > times.now) ret = 100;
        else if (times.highDate > times.now) {
            ret = Math.sqrt((times.timeTilHighest * times.timeTilHighest) / (times.sunRise * times.sunRiseLength)) * 80;
        }
        else if (times.sunSet > times.now) {
            ret = Math.sqrt(((0 - times.timeTilHighest) * (0 - times.timeTilHighest)) / (times.sunRiseLength * times.sunRiseLength)) * 80;
        }
        else if (times.lowDate > times.now) ret = 100;
        else ret = 100;

        endY = (ret / 100 * Timeline.canvas.height) + 100;
        endX = Math.round(Timeline.canvas.width-((ret / 100 * Timeline.canvas.width)+100))

        return endY;

    }


    calculateEndPosition();

    var timetaken = (Timeline.canvas.height-endY)/velY;
    velX = (Timeline.canvas.width-endX)/timetaken;



    this.init = function () {


    }


    this.move = function () {
        if (velX > 0) {
          velX = velX;
        }
        if (x > endX) x += velX;
        if (y > endY) y += velY;
        if (x < 0) x = endX;
        if (y < 0) y = endY;
    }

    this.draw = function () {
        if (endX < 0) return;
        var daylight = weatherApp.times.sunSet.getTime()-weatherApp.times.sunRise.getTime();
        var sunlight = weatherApp.times.now.getTime()-weatherApp.times.sunRise.getTime();
        daylight = daylight/2;
        sunlight = sunlight/2;
        var opacity = Math.abs(sunlight/daylight)*10;
        if (opacity > 1) opacity = 1;
        Timeline.context.fillStyle = "rgba(255, 204, 51," + opacity + ")";
        Timeline.context.beginPath();
        Timeline.context.arc(x, y, radius, 0, Math.PI * 2, true); // Outer circle
        Timeline.context.fill();
        this.move();
    }
}

Timeline = {};

Tools = {
    randomRange: function (min, max) {
        return (Math.random() * (max - min)) + min;
    },

 factorial: function(n) {
  t = this;
  if ((n == 0) || (n == 1))
    return 1
   else {
      result = (n * t.factorial(n-1) )
      return result
   }
},
 sum: function(n) {
  t = this;
  if ((n == 0) || (n == 1))
    return 1
   else {
      result = (n + t.sum(n-1) )
      return result
   }
}
}
Wind = {
    value: 1,

}


weatherApp = {
    canvas: '#canvas',
    log: '#log',
    country: "UK",
    data: {},
    options: {},
    mouse: {},
    coords: {
        latitude: 50.942,
        longitude: -1.1758
    },
    defaultCoords: {
        latitude: 50.942,
        longitude: -1.1758
    },
    defaultLatLong:'50.942,-1.1758',
    minZIndex: 0,
    maxZIndex: 0,
}

Weather = function () {

    var t = this;

    var
    location = new Location(),
        data, overrideLocation = false;

    this.rain = undefined;
    this.snow = undefined;
    this.star = undefined;
    this.sky = undefined;
    this.data = data;
    this.clouds = [];

    Weather = function () {

        return this;
    }

    this.init = function (options) {

        weatherApp.gettingData = true;
        weatherApp.image= 'images/cloud1.png';
        weatherApp.locString='';
        weatherApp.moonPhase='';
        this.clear();
        weatherApp.options = {
            canvas: 'canvas',
            log: 'log',
            location: weatherApp.defaultLatLong,
            parallax: false,
            cloudMinY: 0,
            cloudMaxY: 100,
            moonEndY: 0,
            sunEndY: 0,
            weather: '',
            time: '',
            wind: '',
            useLocalTime: true,
            rgb:{r:0,g:0,b:255},
            checkDataChanged: 60, // check data changed every n seconds
            setWindowSize: false
        };
        weatherApp.ycode = ycode;
        jQuery.extend(weatherApp.options, options);
        weatherApp.canvas = '#' + weatherApp.options.canvas;
        weatherApp.log = '#' + weatherApp.options.log;
        weatherApp.minZIndex = document.getElementById(weatherApp.options.canvas).style.zIndex;
        if (weatherApp.options.address != '') weatherApp.address = weatherApp.options.address;
        if (weatherApp.options.location != 'false') {
           if (weatherApp.options.location == 'true') weatherApp.options.location = '';
        } else {
            weatherApp.options.location = weatherApp.defaultLatLong;
        }

        //GL document.body.style.background = "#aaf";
        $(document).bind("location.found", function () {
            var ll = weatherApp.coords.latitude + "," + weatherApp.coords.longitude;
            weatherApp.latlong = ll;
            $.post("Maps/getinfo.php", {
                p: 'time ' + ll,
                c: weatherApp.country
            }, function (html) {
              if (html.trim() == '') alert('no time for '+ll);
                weatherApp.localTime = html;
                $(weatherApp.log).html('');
                t.getData();
            });
        });

        Timeline = {
            fps: 24,
            totalFrames: -1,
            frame: 0,
            nextFrame: function () {
                if (Timeline.frame === Timeline.totalFrames) {
                    Timeline.stop();
                    return;
                }
                Timeline.frame++;
                Timeline.clear();
                $(document).trigger("timeline.frame");
            },
            clear: function () {
                if (typeof Timeline.canvas != 'undefined') Timeline.context.clearRect(0, 0, Timeline.canvas.width, Timeline.canvas.height)

            },
            start: function () {
                $(document).trigger("timeline.start");
                var timeout = 1000 / Timeline.fps;

                Timeline.interval = window.setInterval("Timeline.nextFrame()", timeout)

            },
            stop: function () {
                $(document).trigger("timeline.stop");
                window.clearInterval(Timeline.interval);
            },
            init: function (id) {
                Timeline.canvas = document.getElementById(id);
                Timeline.context = Timeline.canvas.getContext('2d');
                $(document).trigger("timeline.ready");
            },
            interval: undefined,
            canvas: undefined,
            context: undefined,
        }


        Timeline.init(weatherApp.options.canvas);

        $(document).bind("timeline.begin", function () {
            Timeline.start();
        })


        $(document).bind("timeline.frame", function () {
            t.checkDataChanged();
        })


        $(document).bind("data.ready", function () {

            var w = weatherApp.data;
            if (w == '') return;
            weatherApp.image = "http://l.yimg.com/a/i/us/nws/weather/gr/" + w.item.condition.code + "d.png";
            var wd = w.wind.direction;
            if (wd >= 348.75 && wd <= 360) {
                wd = "N"
            } else
            if (wd >= 0 && wd < 11.25) {
                wd = "N"
            }  else
            if (wd >= 11.25 && wd < 33.75) {
                wd = "NNE"
            } else
            if (wd >= 33.75 && wd < 56.25) {
                wd = "NE"
            } else
            if (wd >= 56.25 && wd < 78.75) {
                wd = "ENE"
            }  else
            if (wd >= 78.75 && wd < 101.25) {
                wd = "E"
            }  else
            if (wd >= 101.25 && wd < 123.75) {
                wd = "ESE"
            }  else
            if (wd >= 123.75 && wd < 146.25) {
                wd = "SE"
            }  else
            if (wd >= 146.25 && wd < 168.75) {
                wd = "SSE"
            }  else
            if (wd >= 168.75 && wd < 191.25) {
                wd = "S"
            }  else
            if (wd >= 191.25 && wd < 213.75) {
                wd = "SSW"
            }  else
            if (wd >= 213.75 && wd < 236.25) {
                wd = "SW"
            }  else
            if (wd >= 236.25 && wd < 258.75) {
                wd = "WSW"
            }  else
            if (wd >= 258.75 && wd < 281.25) {
                wd = "W"
            } else
            if (wd >= 281.25 && wd < 303.75) {
                wd = "WNW"
            }  else
            if (wd >= 303.75 && wd < 326.25) {
                wd = "NW"
            }  else
            if (wd >= 326.25 && wd < 348.75) {
                wd = "NNW"
            };
            var tim = new Date((weatherApp.options.useLocalTime)?createDate(weatherApp.localTime) :w.lastBuildDate);
            weatherApp.time = tim.toString();
            if (weatherApp.options.time != '') {
               weatherApp.time = createDateHHMM(weatherApp.options.time);
            }
            weatherApp.lastBuildDate = w.lastBuildDate;
        var times = {};
        tim = new Date(weatherApp.time);
        times.sunRise = new Date(tim.toDateString() + ' ' + weatherApp.data.astronomy.sunrise);
        times.sunSet = new Date(tim.toDateString() + ' ' + weatherApp.data.astronomy.sunset);
        times.now = tim;
        times.highDate = (times.sunSet.getTime() - times.sunRise.getTime()) / 2 + times.sunRise.getTime();
        times.sunRiseLength = times.highDate - times.sunRise.getTime();
        times.lowDate = times.sunSet.getTime() + times.sunRiseLength;
        times.timeTilHighest = times.highDate - times.now.getTime();

        weatherApp.times = times;
            weatherApp.forecast = "<a href='" + w.item.link + "' target='_blank'>Full Forecast</a>";
            var time = w.lastBuildDate.split(',');
            time = time[1].trim();
            log("Date &amp; Time: " + time);
            log("Temperature: " + t.convert('t', weatherApp.data.item.condition.temp));

            if (weatherApp.data.atmosphere.visibility != '') {
              log("Visibility: " + t.convert('d', weatherApp.data.atmosphere.visibility));
            }
            var pstatus = weatherApp.data.atmosphere.rising;
            var rising = Array('Steady', 'Rising', 'Falling')[pstatus];
            log("Pressure: " + t.convert('p', weatherApp.data.atmosphere.pressure) + ' ' + rising);

            weatherApp.wind = t.convert('s',weatherApp.data.wind.speed,'i');
            Wind.value = weatherApp.wind/4; // mph

            log("Wind: " + t.convert('s', weatherApp.data.wind.speed) + ' ' + wd);

            t.sky = new Sky();

            t.sun = new Sun();
            $(document).bind("timeline.frame", function () {
                t.sun.draw();
            });

            t.moon = new Moon();
            $(document).bind("timeline.frame", function () {
                t.moon.draw();
            });


            weatherApp.weather = weatherApp.data.item.condition.code;
            if (weatherApp.options.weather != '') weatherApp.data.item.condition.code =
            1*weatherApp.options.weather;
            var ydata = ycode[weatherApp.data.item.condition.code];
            var cloudCount = 5*Tools.sum(ydata.cloud);
            var rainDrops = Math.round(500*ydata.rain/10);
            var snowDrops = Math.round(500*ydata.snow/10);
            t.clouds = [];
            var ctype = 1;
            var cmax = Math.max(ydata.snow,ydata.rain);
            if (cmax > 0) {
              ctype = 2;
              if (cmax > 4) ctype = 3;
            }
            for (var i = 0; i < cloudCount; i++) {
                var cloud = new Cloud(ctype);
                t.clouds.push(cloud);
            }

            $(document).bind("timeline.frame", function () {
                for (i in t.clouds) {
                    t.clouds[i].nextFrame();
                }
            });

            if (weatherApp.options.parallax) {
                var parallax = new Parallax();
            }
            var ytext = ydata.text;
            var p = ytext.indexOf('(');
            if (p > -1) ytext = ytext.substr(0,p);
            log("Weather: " + ytext.trim());


            if (snowDrops>0) {
                t.snow = new Snow(snowDrops);
                $(document).bind("timeline.frame", function () {
                    t.snow.snow();
                });
            }

            if (rainDrops>0) {
                t.rain = new Rain(rainDrops);
                $(document).bind("timeline.frame", function () {
                    t.rain.rain()
                });
            }
            if ((rainDrops == 0) && (snowDrops == 0)) {
                if ((cloudCount < 25) && (weatherApp.opacity > 0.6)) {
                    t.star = new Star(Math.round(1.5 * (25 - cloudCount)));
                    $(document).bind("timeline.frame", function () {
                        t.star.star()
                    });
                }
            }

        weatherApp.gettingData = false;


        });

        $(document).bind("data.ready", function () {
            $(document).trigger("timeline.begin");

        });

        if (typeof weatherApp.options.location == 'object') {
            weatherApp.coords = weatherApp.options.location;
            $(document).trigger("location.found");
        } else {
            location.init(weatherApp.options.location);
        }



    }

    this.getData = function (check) {
       var t = this;
       check = (typeof check == 'undefined')?false:check;
       if (!check) {
          t.findWeatherStation();
       } else {
         t.getWeather(check);
       }
    }


    this.getWeather = function(check){
                var t = this;
                var locString = weatherApp.weatherStation;
                var url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20location%20in%20(select%20id%20from%20weather.search%20where%20query%20%3D%20%22" + locString + "%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=?";

                $.getJSON(url, function (data) {
                    if (data.query.count == '0') {
                      alert('No weather data for '+locString);
                      Timeline.stop();
                      weatherApp.data = '';
                      weatherApp.gettingData = false;
                    } else {
                    if (data.query.results.channel) {
                        if (data.query.results.channel.item) {
                            weatherApp.data = data.query.results.channel;
                        } else {
                            weatherApp.data = data.query.results.channel[0];
                        }
                    } else {
                        weatherApp.data = data.query.results[0];
                    }
                    }
                    if (check) {
                      var comp = (weatherApp.data.lastBuildDate != weatherApp.lastBuildDate)?true:false;
                      if (comp) {
                         weatherApp.options.dataChanged();
                      }
                      return;
                    }
                    $(document).trigger("data.ready");

                })
    }

    this.findWeatherStation = function() {
        // get location string from long / lat
        var ll = weatherApp.coords.latitude + "," + weatherApp.coords.longitude;

        //log("LonLat: "+ll);

        var url = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20geo.placefinder%20where%20text%20%3D%20%22" + ll + "%22%20and%20gflags%3D%22R%22&format=json&callback=?";
        $.getJSON(url, function (data) {
            try {
                var results = data.query.results;
                var Result = results.Result;
                var country = Result.country;
                var locString = Result.city + ", " + Result.country;

                if (country == 'United Kingdom') country = 'UK';
                weatherApp.locString = Result.city+", "+country;
                if (overrideLocation !== false) locString = overrideLocation;
                weatherApp.location = data.query.results
                log("Location: " + weatherApp.locString);
                weatherApp.weatherStation = locString;
                t.getWeather(false);
            } catch (e) {
                alert("Couldn't find any information about your location - " + ll);
                weatherApp.coords = weatherApp.defaultCoords;
                location.init('');

            }
        });

    }

    this.checkDataChanged = function(){
      var t = this;
        var seconds = Timeline.frame / Timeline.fps;
        if ((seconds % weatherApp.options.checkDataChanged) == 0) {
           t.getData(true);
           t.sky.draw();
        }
    }

    this.clear = function () {
        if (typeof Timeline.stop != 'undefined') {
            Timeline.stop();
        }
        this.rain = undefined;
        this.snow = undefined;
        this.star = undefined;
        this.sky = undefined;
        this.data = data;
        this.clouds = [];
/*
        var events = $(document).data('events').timeline;
        for(var i in events) {
           if (events[i].namespace != 'frame') continue;
           events[i].handler = 'function(){}';
           //$(document).unbind("timeline.frame",events[i].handler);
        }
        */
        $(document).unbind();
    }

    this.convert = function (m, data, runits) {
        var units;
        data = parseFloat(data);
        var i;
        if (m == 's') units = weatherApp.data.units.speed;
        if (m == 't') units = weatherApp.data.units.temperature;
        if (m == 'p') units = weatherApp.data.units.pressure;
        if (m == 'd') units = weatherApp.data.units.distance;
        if (units == 'in') {
            var cm = Math.round(2.54 * data, 2);
            var out = data + 'in or ' + cm + 'cm';
            i = Array(data,cm);
        } else if (units == 'cm') {
            var inch = Math.round(0.394 * data, 2);
            var out = data + 'cm or ' + inch + 'in';
            i = Array(inch,data);
        } else if (units == 'F') {
            var deg = (5 * (data - 32)) / 9;
            deg = Math.round(deg);
            out = data + "F or " + deg + "C";
            i = Array(data,deg);
        } else if (units == 'C') {
            deg = 32 + ((5 * data) / 9);
            deg = Math.round(deg);
            out = data + "C or " + deg + "F";
            i = Array(deg,data);
        } else if (units == 'mph') {
            var kph = Math.round((8 / 5) * data, 2);
            out = data + 'mph or ' + kph + 'kph';
            i = Array(data,kph);
        } else if (units == 'kph') {
            var mph = Math.round((5 / 8) * data, 2);
            out = data + 'kph or ' + mph + 'mph';
            i = Array(mph,data);
        } else if (units == 'mi') {
            var kph = Math.round((8 / 5) * data, 2);
            out = data + 'mi or ' + kph + 'km';
            i = Array(data,kph);
        } else if (units == 'km') {
            var mph = Math.round((5 / 8) * data, 2);
            out = data + 'km or ' + mph + 'mi';
            i = Array(mph,data);
        }
        if (typeof runits == 'undefined') {
           return out;
        } else {
          runits = (runits == 'm')?1:0;
          return i[runits];
        }
    }
    return this;
}


function log(str) {
    $(weatherApp.log).append("<p>" + str + "</p>");

}



$(document).bind("timeline.ready", function () {

    onResize();
    $(window).resize(function () {
        resizeTimer = setTimeout("onResize()", 100);
    })

})

onResize = function () {

    var innerHeight = (weatherApp.options.setWindowSize) ? window.innerHeight : $(weatherApp.canvas).height();
    var innerWidth = (weatherApp.options.setWindowSize) ? window.innerWidth : $(weatherApp.canvas).width();
    Timeline.canvas.height = innerHeight;
    Timeline.canvas.width = innerWidth;

    Timeline.context.canvas.height = innerHeight;
    Timeline.context.canvas.width = innerWidth;

}

