#!/usr/bin/python
 
# Copyright 2009-2010 Brandon Stafford
#
# This file is part of Pysolar.
#
# Pysolar is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# Pysolar is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with Pysolar. If not, see <http://www.gnu.org/licenses/>.

"""This script rectifies spherically distorted images in order to detect the
angle to solar obstructions. It is not used in Pysolar's ephemeris
calculations.

An example of this script in action appears here:

http://pingswept.org/2009/03/16/calculating-solar-panel-shading-in-python/

"""
from PIL import Image
from math import *
import numpy as np
import solar
import datetime as dt
import simulate as sim
import radiation as rad

def squareImage(im):
    (width, height) = im.size
    box = ((width - height)/2, 0, (width + height)/2, height)
    return im.crop(box)

def despherifyImage(im):
    (width, height) = im.size
    half_width = im.size[0]/2
    half_height = im.size[1]/2

    inpix = im.load()
    out = Image.new("L", (width, half_height))
    outpix = out.load()

    full_circle = 1000.0 * 2 * pi

#    for r in range(half_width):
#        for theta in range(int(full_circle)):
#            (inx, iny) = (round(r * cos(theta/1000.0)) + half_width, round(r * sin(theta/1000.0)) + half_width)
#            (outx, outy) = (width - width * (theta/full_circle) - 1, r)
#            outpix[outx, outy] = inpix[inx, iny]

    theta_range = range(int(full_circle))
    t_1000_range = [t / 1000.0 for t in theta_range]
    thetas = zip([cos(t) for t in t_1000_range],
    [sin(t) for t in t_1000_range],
    [t / full_circle for t in theta_range])

    for r in range(half_width):
        for t_cos, t_sin, t_full_circle in thetas:
            (inx, iny) = (round(r * t_cos) + half_width,
            round(r * t_sin) + half_width)
            outx = width - width * (t_full_circle) - 1
#            print inpix, outx, r, inx, iny
            outpix[outx, r] = inpix[inx, iny]
    return out



def differentiateImageColumns(im):
    (width, height) = im.size
    pix = im.load()

    for x in range(width):
        for y in range(height - 1):
            pix[x, y] = min(10 * abs(pix[x, y] - pix[x, y + 1]), 255)

    return im

def redlineImage(im):
    (width, height) = im.size
    pix = im.load()

    threshold = 300
    horizon = []

    for x in range(width):
        for y in range(height - 1):
            (R, G, B) = pix[x, y]
            if R + G + B > threshold:
                pix[x, y] = (255, 0, 0)
                horizon.append(y)
                break
    return (im, horizon)

def addSunPaths(im, latitude_deg, longitude_deg, horizon, d):
    pix = im.load()

    alt_zero = getAltitudeZero()
    az_zero = getAzimuthZero()

    for m in range(24 * 60):
        alt = solar.GetAltitude(latitude_deg, longitude_deg, d + dt.timedelta(minutes = m))
        az = solar.GetAzimuth(latitude_deg, longitude_deg, d + dt.timedelta(minutes = m))

        x = az_zero + int(az * 1944.0/360.0)
        y = alt_zero - int(alt_zero * sin(radians(alt)))
        if y < horizon[x]:
            pix[x % 1944, y] = (255, 193, 37)
    
    return im

def getAzimuthZero():
    return 1100

def getAltitudeZero():
    return 380

if __name__ == '__main__':
    horizon = []

    im = Image.open('spherical.jpg').convert("L")
    im = squareImage(im)

    print 'Starting despherification . . .'
    lin = despherifyImage(im)

    print 'Despherification complete. Calculating horizon . . .'
    d = differentiateImageColumns(lin).convert("RGB")
    r, horizon = redlineImage(d)
    print 'Horizon calculated.'

    (latitude_deg, longitude_deg) = (42.206, -71.382)
    summer = dt.datetime(2009, 6, 21, 5, 0, 0, 0)
    fall = dt.datetime(2009, 9, 21, 5, 0, 0, 0)
    winter = dt.datetime(2009, 12, 21, 5, 0, 0, 0)
    step_minutes = 5

    power_densities = [radiation for (time, alt, az, radiation, shade) in sim.SimulateSpan(latitude_deg, longitude_deg, horizon, summer, winter, step_minutes)]
    print power_densities

    energy = sum(power_densities) * step_minutes * 60
    print str(energy/1000000) + ' MJ per m^2 per year'

    sp = addSunPaths(r, latitude_deg, longitude_deg, horizon, summer)
    sp2 = addSunPaths(r, latitude_deg, longitude_deg, horizon, fall)
    sp3 = addSunPaths(r, latitude_deg, longitude_deg, horizon, winter)

    sp3.show()

#   sp3.save('sun_path.jpg')
