# Copyright (C) 2020 Fintic, finticofficial@gmail.com
#
# This file is part of Fintic project, developed by Neythen Treloar and Justin Dunn
#
# stockTicker can not be copied and/or distributed without the express
# permission of Fintic


import sys, select
import os
import threading
from PIL import Image, ImageDraw, ImageFont, ImageSequence

Image.init()

import time
import csv
import requests
import pexpect
from rgbmatrix import RGBMatrix, RGBMatrixOptions
from rgbmatrix.graphics import *
from multiprocessing import Process
import traceback 
import json
from datetime import datetime
import matplotlib.colors as mcolors

def getInput(Block=False):
    if Block or select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
        msg = sys.stdin.read(1)
        #sys.stdin.flush()
    else:
        msg = ''
    return msg


  
class StockTicker():
    def __init__(self):
        #Define global resources
        self.symbols = []
        self.delay = 0.02
        self.greenORred = (255, 255, 255)
        #self.blank = Image.open('logos/blank.png')
        self.blank = Image.new('RGB', (10, 32))
        self.running = True
        
        settings = json.load(open('csv/general_settings.json', 'r'))
        
        
        self.brightness =  settings['brightness']*10
            
        # Configuration for the matrix
        options = RGBMatrixOptions()
        options.rows = 32
        options.cols = 64
        options.chain_length = 2
        options.parallel = 1
        options.hardware_mapping = 'adafruit-hat' # If you have an Adafruit HAT: 'adafruit-hat'
        options.gpio_slowdown = 4
        options.brightness = self.brightness
        self.matrix = RGBMatrix(options = options)
        print(dir(self.matrix))
        #sys.exit()
        self.points = True # display crypto change in points or percent
     
        self.functions = {'Stocks': self.getStockImage, 'Crypto': self.getCryptoImage, 'Forex': self.getForexImage, 
                'Daily Forecast':self.getDailyWeatherImage, 'Current Weather': self.getTodayWeatherImage, 
                'Sports (Team Stats)':lambda : self.getLeagueTableImage('premier_league'), 'Sports (Past Games)': lambda:self.getLeagueImage('NBA', 'past'), 
                'Sports (Upcoming Games)': lambda : self.getLeagueImage('NHL', 'future'), 'Sports (Live Games)': lambda: self.getLeagueImage('NBA', 'live'), 
                'News':self.getNewsImage, 'Custom Messages': self.getUserMessages, 
                
                
                'Stocks Prof': self.getStockProfessional, 'Crypto Prof': self.getCryptoProfessional, 'Forex Prof': self.getForexProfessional, 
                'Current Weather Prof': self.getTodayWeatherProfessional, 'News Prof':self.getNewsProfessional} 
                
        self.JSONs = {'Stocks': 'csv/stocks_settings.json', 'Crypto': 'csv/crypto_settings.json', 'Forex': 'csv/forex_settings.json', 
                'Daily Forecast':'csv/daily_weather.json', 'Current Weather': 'csv/current_weather.json', 
                'Sports (Team Stats)': 'csv/league_tables.json', 'Sports (Past Games)': 'csv/past_games.json', 
                'Sports (Upcoming Games)': 'csv/upcoming_games.json', 'Sports (Live Games)': 'csv/live_games.json', 
                'News':'csv/news_settings.json', 'Custom Images': 'csv/image_settings.json', 'Custom GIFs': 'csv/GIF_settings.json', 'Custom Messages': 'csv/message_settings.json',
                'Stocks Prof': 'csv/stocks_settings.json', 'Crypto Prof': 'csv/crypto_settings.json', 'Forex Prof': 'csv/forex_settings.json', 
                'Current Weather Prof': 'csv/current_weather.json', 'News Prof':'csv/news_settings.json'}
        

    def openImage(self, image_file):
        image = Image.open(image_file)
        image = image.convert('RGB')
         # Make image fit our screen.
        #image.thumbnail((self.matrix.width, self.matrix.height), Image.ANTIALIAS)

        #image = image.convert('RGB')
        return image
    
    def degreesToCompass(self, deg):
        
        dirs = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW']
        
        return dirs[int((deg+22.5)//45)%8]
 
    def setImage(self, image, offset_x = 0, offset_y = 0, unsafe=True, min_x = 0, max_x = 128, min_y = 0, max_y = 32):
        
        
        if (image.mode != "RGB"):
            image = image.convert('RGB')

        if unsafe:
            #In unsafe mode we directly acceshow to send commands to running python processs the underlying PIL image array
            #in cython, which is considered unsafe pointer accecss,
            #however it's super fast and seems to work fine
            #https://groups.google.com/forum/#!topic/cython-users/Dc1ft5W6KM4
            img_width, img_height = image.size
            
            self.matrix.SetPixelsPillow(offset_x, offset_y, img_width, img_height, image)
        else:
            # First implementation of a SetImage(). OPTIMIZE_ME: A more native
            # implementation that directly reads the buffer and calls the underlying
            # C functions can certainly be faster.
            img_width, img_height = image.size
            pixels = image.load()
            for y in range(max(0, -offset_y), min(img_height, self.matrix.height - offset_y)):
             
                for x in range(max(0, -offset_x), min(img_width, self.matrix.width - offset_x)):

                    if min_x <= x + offset_x <= max_x and min_y <= y + offset_y <= max_y:
                        (r, g, b) = pixels[x, y]
                        self.matrix.SetPixel(x + offset_x, y + offset_y, r*self.brightness, g*self.brightness, b*self.brightness)
            
    def scrollImage(self, image, offset_x = 0, offset_y = 0, frame_skip = 10, gif = False, pause_frames = 0):
        img_width, img_height = image.size
        kill = False
        while offset_x > -(img_width+1):
            if offset_x == 0:
                while pause_frames > 0:
                    if pause_frames%frame_skip  == 0:
                        self.incrementGIF(image)
                    
                    pause_frames -=1
                    if gif:
                        self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
                        
                    else:
                        self.double_buffer.SetImage(image, offset_x, offset_y)
                    
                    for y in range(self.matrix.height):
                        self.matrix.SetPixel(offset_x + img_width +1 , y , 0,0,0)
                        self.matrix.SetPixel(offset_x + img_width  , y , 0,0,0)
                                
                
                    self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
                    
                    time.sleep(self.delay)
                    kill = self.checkKilled()
                    if kill: break
            if kill: break
            # for animation in gifs
            if offset_x%frame_skip  == 0:
                self.incrementGIF(image)

            #image = image.convert('RGB')
            offset_x -= 1

            #self.setImage(image.convert('RGB'), offset_x = offset_x, offset_y = offset_y)
            if gif:
                
                self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
            else:
                self.double_buffer.SetImage(image, offset_x, offset_y)
                
            buff = 0

            # remove the ppixels behind the image, to stop trailing    
            self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
            for y in range(self.matrix.height):
                self.matrix.SetPixel(offset_x + img_width +1 , y , 0,0,0)
                self.matrix.SetPixel(offset_x + img_width  , y , 0,0,0)
                
      
            time.sleep(self.delay)
            kill = self.checkKilled()

            if kill: break
        return kill
    
    def scrollImageY(self, image, direction = 1,  offset_x = 0, offset_y = 0, frame_skip = 10, gif = False):
        kill = False
        while offset_y != 0:
                    
            # for animation in gifs
            if offset_y%frame_skip == 0:
              
                self.incrementGIF(image)

            offset_y += direction

            if gif:
                self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
                
            else:
                self.double_buffer.SetImage(image, offset_x, offset_y)
                
            self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
            
            time.sleep(self.delay)
            kill = self.checkKilled()
            if kill: break
            
        return kill 
        
    def scrollImageTransition(self, image_files, offset_x = 0, offset_y = 0, stocks = True):
        # use two image files and switch between them with a seemless transition
        current_img = 1
        image1 = self.openImage(image_files[0]).convert('RGB')
        image2 = self.openImage(image_files[1]).convert('RGB')
        
        double_buffer = self.matrix.CreateFrameCanvas()
        kill = False 
        while True:
            
            if current_img == 1:
                
                if stocks: 
                    update_process = Process(target = self.getFullStockImage, args = (1,))
                    update_process.start()
                    image1 = self.openImage(image_files[0]).convert('RGB')
                    image2 = self.openImage(image_files[1]).convert('RGB')
                
            elif current_img == 2:
               
                if stocks: 
                    update_process = Process(target = self.getFullStockImage, args = (2,))
                    update_process.start()
                    
                    image1 = self.openImage(image_files[1]).convert('RGB')
                    image2 = self.openImage(image_files[0]).convert('RGB')
            
            img_width, img_height = image1.size
            
            
            while offset_x > -img_width:
                offset_x -= 1
                
                double_buffer.SetImage(image1, offset_x, offset_y)
                
                
                if offset_x + img_width < self.matrix.width: # if the image is ending
                    double_buffer.SetImage(image2, offset_x, offset_y)
                
                double_buffer = self.matrix.SwapOnVSync(double_buffer)
                
                time.sleep(self.delay)
                kill = self.checkKilled()
                if kill: break
                
            if stocks:
                image1.close()
                image2.close()
                        
            if kill: break
            
            if stocks:
                update_process.join()
                update_process.terminate()
            if current_img == 1:
                current_img = 2 
            elif current_img == 2:
                current_img = 1 
            offset_x = 0
            update_process.join()
            update_process.terminate()
        
    def scrollImageStacked(self, image, offset_x = 0, offset_y = 0):
        img_width, img_height = image.size
        
        

        while offset_x > -img_width - 128:
            offset_x -= 1
            
            self.setImage(image, offset_x = offset_x+128, offset_y = offset_y)
            self.setImage(image, offset_x = offset_x, offset_y = offset_y+20)
            
            kill = self.checkKilled()
                    
            time.sleep(self.delay)
        return kill
            
    def updateMultiple(self, options):
        print('options', options)
        for option in options:
            
            
            if option not in ['Custom GIFs', 'Custom Images', 'Custom Messages']: # these images are already saved in user uploads, dodnt need to update them 
                img = self.functions[option]()
                img.save('./display_images/'+ option+ '.ppm')
         
    
    def incrementGIF(self, image):
        try:
            image.seek(self.frame)
        except EOFError:
            self.frame = 0
            image.seek(self.frame)
        self.frame +=1
                
    def checkKilled(self):
        
        kill = False
        try:
            msg = getInput()
            
            if msg == 'K':
                self.resetMatrix()
                kill = True
            self.process_msg(msg)
        except KeyboardInterrupt:
            sys.stdout.flush()
            pass
        return kill
    
    def set_delay(self,speed):
        if speed.lower() == 'slow':
            self.delay = 0.03
        elif speed.lower() == 'medium':
            self.delay = 0.02
        elif speed.lower() == 'fast':
            self.delay = 0.01
        return self.delay
            
        
    def scrollFunctionsAnimated(self, options, animation = 'down', repeat = True):
        
        # scrolls trhough all functions with animation. Updates functions and remakes images when each function not being dispplayed 
        
        self.updateMultiple([options[0]])
 
        
        kill = False 
        i = 0 # keep track of which image we are displaying
        self.double_buffer = self.matrix.CreateFrameCanvas()
        
        while True:
            
            update_process = Process(target = self.updateMultiple, args = ([options[(i+1) % len(options)]],))
            update_process.start()
            
            settings = json.load(open(self.JSONs[options[(i) % len(options)]]))
        
            self.set_delay(settings['speed'])
            animation = settings['animation'].lower()
            
            if options[i % len(options)]  == 'Custom Images':
                images = self.getUserImages()
                
            elif options[i % len(options)]  == 'Custom GIFs':
                images = self.getUserGIFs()
                
            elif options[i % len(options)]  == 'Custom Messages':
                images = self.getUserMessages()
                
            
            else: #these options just have a single ppm image
                image = self.openImage('./display_images/' + options[i % len(options)] +'.ppm')
                
                images = [image]
                
            
            for image in images:
                img_width, img_height = image.size
                
                offset_x = 0
                if animation == 'continuous':
                    offset_x = 128
                elif animation in ['up', 'down']:
                    offset_x = max(0, 128-img_width)
                
                offset_y = 0
                #first scroll image in from bottom
                
                
                
                frame_skip = int((1/15)/self.delay) #controls how fast gifs run 
                self.frame = 0
                
                pause_frames = int(0.5/self.delay)
                if animation == 'up':
                    offset_y = 33
                    direction = -1
                    kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs')
                elif animation == 'down':
                    direction = 1
                    offset_y = -33
                    kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs')
                    
                if kill: break
                offset_y = 0
                
                
                if animation in ['up', 'down']:
                    while pause_frames > 0:
                        if pause_frames%frame_skip  == 0:
                            self.incrementGIF(image)
                        
                        pause_frames -=1
                        if options[i % len(options)] != 'Custom GIFs':
                            self.double_buffer.SetImage(image, offset_x, offset_y)
                        else:
                            self.double_buffer.SetImage(image.convert('RGB'), offset_x, offset_y)
                    
                        self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
                        
                        time.sleep(self.delay)
                        kill = self.checkKilled()
                        if kill: break
                    
                    
                    if kill: break
                    
                           
                if kill: break
                try: 
                    pause = float(settings['pause'])
                except:
                    pause = 0
                pause_frames = int(float(pause)/self.delay) 
                kill = self.scrollImage(image, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = options[i % len(options)] == 'Custom GIFs', pause_frames = pause_frames)
                
                if kill: break
            if kill:break
            if not repeat:
                break
            update_process.join()
            update_process.terminate()
            i+=1
            
    def scrollProfessionalAnimated(self, options, animation = 'on'):
        
        # scrolls trhough all functions with animation. Updates functions and remakes images when each function not being dispplayed 
        
        top = options[0]
        bottom = options[1]
        
       
        
        self.updateMultiple([top[0], bottom[0]])

        kill = False 
        i1 = 0 # keep track of which image we are displaying
        i2 = 0 # keep   track of which image we are displaying
        
        self.double_buffer = self.matrix.CreateFrameCanvas()
        update_process = Process(target = self.updateMultiple, args = ([top[(i1+1) % len(top)]+ ' Prof', bottom[(i2+1) % len(bottom)]+ ' Prof' ],))
        
        update_process.start()
 
        self.updateMultiple([top[i1 % len(top)]+ ' Prof', bottom[i2 % len(bottom)]+ ' Prof' ])
        
        
        image1 = self.openImage('./display_images/' + top[i1 % len(top)] +' Prof.ppm')
        image1 = image1.convert('RGB')
        

        image2 = self.openImage('./display_images/' + bottom[i2 % len(bottom)] +' Prof.ppm')
        image2 = image2.convert('RGB')
        
        
        settings1 = json.load(open(self.JSONs[top[i1 % len(top)]]))
                
        delay_t1 = self.set_delay(settings1['speed'])
        animation1 = settings1['animation'].lower()
        
        settings2 = json.load(open(self.JSONs[bottom[i2 % len(bottom)] ]))
        delay_t2 = self.set_delay(settings2['speed'])
        animation2 = settings2['animation'].lower()

        if animation1 == 'continuous':
            offset_y1 = 0
            offset_x1 = 128
        else:
            offset_y1 = -16
            offset_x1 = 0
            
        if animation2 == 'continuous':
            offset_y2 = 16
            offset_x2 = 128
        else:
            offset_y2 = 32
            offset_x2 = 0
        
        
        frame_skip = int((1/15)/self.delay) #controls how fast gifs run 
        self.frame = 0
        
        img_width1, img_height1 = image1.size
        img_width2, img_height2 = image2.size
        kill = False
        
        update_t1 = time.time()
        update_t2 = time.time()
        while True:
            
            if offset_x1 < -(img_width1+1):
                i1 += 1
                settings1 = json.load(open(self.JSONs[top[i1 % len(top)]]))
                
                delay_t1 = self.set_delay(settings1['speed'])
                animation1 = settings1['animation'].lower()
                
                if animation1 == 'continuous':
                    offset_y1 = 0
                    offset_x1 = 128
                else:
                    offset_y1 = -16
                    offset_x1 = 0
                
                update_process.join()
                update_process.terminate()
                update_process = Process(target = self.updateMultiple, args = ([top[(i1+1) % len(top)]+ ' Prof'],))
                update_process.start()
                image1 = self.openImage('./display_images/' + top[i1 % len(top)] +' Prof.ppm')
                image1 = image1.convert('RGB')
                img_width1, img_height1 = image1.size
                
            if offset_x2 < -(img_width2+1):
                i2 += 1
                settings2 = json.load(open(self.JSONs[bottom[(i2) % len(bottom)]]))
                delay_t2 = self.set_delay(settings2['speed'])
                animation2 = settings2['animation'].lower()
                
                if animation2 == 'continuous':
                    offset_y2 = 16
                    offset_x2 = 128
                else:
                    offset_y2 = 32
                    offset_x2 = 0
                
                
                update_process.join()
                update_process.terminate()
                update_process = Process(target = self.updateMultiple, args = ([bottom[i2 % len(bottom)]+ ' Prof'],))
                update_process.start()
                image2 = self.openImage('./display_images/' + bottom[(i2+1) % len(bottom)] +' Prof.ppm')
                image2 = image2.convert('RGB')
                img_width2, img_height2 = image2.size
                
            
            if time.time() - update_t1 > delay_t1:
                update_t1 = time.time()
                if offset_y1 < 0:
                    offset_y1+=1
                else:
                    offset_x1 -= 1
                    
            if time.time() - update_t2 > delay_t2:
                update_t2 = time.time()
                if offset_y2 > 16:
                    offset_y2-=1
                else:
                    offset_x2 -= 1
               
            if kill: break
        
            #image = image.convert('RGB')
            
            

            self.double_buffer.SetImage(image1, offset_x1, offset_y1)
            self.double_buffer.SetImage(image2, offset_x2, offset_y2)
                
            buff = 0

            # remove the ppixels behind the image, to stop trailing    
            self.double_buffer = self.matrix.SwapOnVSync(self.double_buffer)
            for y in range(16):
                self.matrix.SetPixel(offset_x1 + img_width1 +1 , y , 0,0,0)
                self.matrix.SetPixel(offset_x1 + img_width1  , y , 0,0,0)
            for y in range(16,32):
                self.matrix.SetPixel(offset_x2 + img_width2 +1 , y , 0,0,0)
                self.matrix.SetPixel(offset_x2 + img_width2  , y , 0,0,0)
                
      
            
            kill = self.checkKilled()
            
            if kill: break
                
            
            if kill: break
            
            
             
    def scrollMultiple(self, animation = 'down'):
        # scrolls trhough all functions with animation. Updates functions and remakes images when each function not being dispplayed 
        
        # read lines from csv 
        images = []
        delays = []
        kinds = []
   
        f = open('csv/multiple.csv', 'r')
        CSV = csv.reader(f)
        next(CSV)
        font = ImageFont.load("./fonts/texgyre-27.pil")
        
        for row in CSV:
            
            
            kind, content, delay = row
            delays.append(delay)
            kinds.append(kind)
            print(kind, content, delay)
            if kind == 'text':
                images.append(self.textImage(content, font, 255, 255, 0, True, w_buff = 50))
            elif kind == 'image':
                images.append(self.openImage(content).convert('RGB'))
            elif kind == 'gif':
                images.append(self.openImage(content))
        f.close()
        
        
        kill = False 
        i = 0 # keep track of which image we are displaying
        self.double_buffer = self.matrix.CreateFrameCanvas()
        while True:
            image = images[i%len(images)]
            delay = delays[i%len(images)]
            kind = kinds[i%len(images)]
            

            
            img_width, img_height = image.size
            
            offset_x = 0
            if animation == 'traditional':
                offset_x = 128
            elif animation == 'continuous':
                offset_x = 0
            elif animation in ['up', 'down']:
                offset_x = max(0, 128-img_width)
            
            offset_y = 0
            #first scroll image in from bottom
            
            frame_skip = int((1/15)/self.delay) #controls how fast gifs run 
            self.frame = 0
            
            pause_frames = int(float(delay)/self.delay) 
            if animation == 'up':
                offset_y = 33
                direction = -1
                kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = kind=='gif')
            elif animation == 'down':
                direction = 1
                offset_y = -33
                kill = self.scrollImageY(image, direction = direction, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = kind=='gif')
     
            
            offset_y = 0
            if kill: break
            
            kill = self.scrollImage(image, offset_x = offset_x, offset_y = offset_y, frame_skip = frame_skip, gif = kind=='gif', pause_frames = pause_frames)
            
            if kill: break
            i+=1
    
    def textImage(self, text, font, r = 255, g = 255, b = 255, matrix_height = False, w_buff = 3, h_buff = 3, background = False, location = False):
        '''
        creates and returns a ppm image containing the text in the supplied font and colour
        '''
        
        width, height = self.get_text_dimensions(text, font)
        
        if matrix_height:
            height = 32
        img = Image.new('RGB', (width + w_buff, height + h_buff))
        d = ImageDraw.Draw(img)
        
        if background:
            br, bg, bb = background
            d.rectangle(xy = (0, 0, width + w_buff, height + h_buff),
               fill = (br, bg, bb))
        #outline = (255, 255, 255),
        #width = 0) #use outline and width to add a border
        if location:
            d.text(location, text, fill=(r, g, b), font=font)
        else:
            d.text((0, 0), text, fill=(r, g, b), font=font)
        return img
        

    def getUserMessages(self):
        '''
        displays the text entered in the webpage by the user.
        '''
     
        
        
        f = open('csv/message_settings.json', 'r')
        all_settings = json.load(f)
        f.close()
        
        
        
        colours = {'Black':(0,0,0),
                   'White':(255,255,255),
                    'Red':(255,0,0),
                    'Green':(0,255,0),
                    'Blue':(0,0,255),
                    'Purple':(255,0,255),
                    'Yellow':(255,255,0),
                    'Cyan':(0,255,255)}
        imgs = []
        for ind, message in enumerate(all_settings['messages']):
            
            font = ImageFont.load("./fonts/10x20.pil")
            location = (0, 4)
            if message["size"] == 'Large':
                font = ImageFont.load("./fonts/texgyre-27.pil")
                location = (0, -2)
            elif message["size"] == 'Small':
                font = ImageFont.load("./fonts/6x13.pil")
                location = (0, 7)
                
                
            r,g,b = colours[message['text_colour']]

            background = colours[message['background_colour']]
            img = self.textImage(message['text'], font, int(r), int(g), int(b), True, w_buff = 5, background = background, location = location)
            
            
            if all_settings['title'] and ind == 0:
                title_img = self.openImage('feature_titles/message.png')
                imgs.append(self.stitchImage([title_img, img]))
            else:
                
                imgs.append(img)
        
        
        return imgs

    def displayGIF(self, gif, delay = 0.5, repeat = True):
        # To iterate through the entire gif
        i = 0
        while True:
            try:
                gif.seek(i)
            except EOFError:
                if not repeat: break
                i = 0
                gif.seek(i)
            # do something to im
            self.setImage(gif.convert('RGB'))
            time.sleep(delay)
            i += 1
            try:
                msg = getInput()
               
                if msg == 'K':
                    gif.close()
                    self.resetMatrix()
                
                    break
            
                self.process_msg(msg)
            except KeyboardInterrupt:
                sys.stdout.flush()
                pass
                
    def scrollGIF(self, gif, offset_x = 0, offset_y = 0):
        # To iterate through the entire gif
        i = 0
        
        img_width, img_height = gif.size

        while offset_x > -img_width:
            offset_x -= 1
      
            try:
                gif.seek(i)
            except EOFError:
          
                i = 0
                gif.seek(i)
            # do something to im
            self.setImage(gif.convert('RGB'), offset_x = offset_x)
            time.sleep(self.delay)
            
            if offset_x % 20 == 0:
                i += 1
                
            for x in range(offset_x + img_width, 128):
                for y in range(self.matrix.height):

                    self.matrix.SetPixel(x , y , 0,0,0)

            kill = self.checkKilled()
            if kill:
                break
        return kill
                  
    #Using change between min and day price give appropriate arrow
    #and set the overall change colour
    def getArrow(self, CHANGE, professional = False):
        self.greenORred
        logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'stocks')
        if(CHANGE>0):
            Arrow = Image.open(os.path.join(logos_path, 'up-1.png'))
            self.greenORred = (0, 255, 0)
            
        else:
            Arrow = Image.open(os.path.join(logos_path, 'down-1.png'))
            self.greenORred = (255, 0, 0)
            CHANGE = (CHANGE * -1)
        
        if professional:
            w, h = Arrow.size
            Arrow = Arrow.resize((int(w/2), int(h/2)))
        return Arrow, CHANGE

    def get_text_dimensions(self, text_string, font):
        canvas = Image.new('RGB', (10000,100))

        draw = ImageDraw.Draw(canvas)
        monospace = font

        text = text_string
        white = (255,255,255)
        draw.text((0, 0), text, font=monospace, fill=white)

        bbox = canvas.getbbox()
        width = bbox[2]-bbox[0]
        height = bbox[3]-bbox[1]

        return width,height

    #Draw Ticker, current and change onto one image
    def textToImage(self, TICKER, CURRENT, ARROW, percent_change = False, point_change = False, font = ImageFont.load("./fonts/10x20.pil")):
        w1, text_height = self.get_text_dimensions(TICKER, font)
        w2, text_height = self.get_text_dimensions(CURRENT, font)
        
        
        text_width_current = max(w1,w2)
        
        img = Image.new('RGB', (text_width_current  +1000 , 32))
        d = ImageDraw.Draw(img)

        d.text((4, 0), TICKER, fill=(255, 255, 255), font=font)
        d.text((4, 16), CURRENT, fill=self.greenORred, font=font)

        if percent_change:
            d.text(((w1+7), 14 - text_height), percent_change, fill=self.greenORred, font=font)
            w, h = self.get_text_dimensions(percent_change, font)
            w1 += 7 + w
            
            
            
        if point_change:
            img.paste(ARROW, ((w2+ 9),18))
            d.text(((w2+29), 16), point_change, fill=self.greenORred, font=font)
            w,h = self.get_text_dimensions(point_change, font)
            w2 += 29 + w
        
        

        img = img.crop((0,0,max(w1, w2) + 20,32)) 
        return img 
        
    def textToImageProf(self, TICKER, CURRENT, CHANGE, ARROW, font):
        
        text_width_current, text_height = self.get_text_dimensions(CURRENT, font)
        
        img = Image.new('RGB', (text_width_current  +100 , 32))
        d = ImageDraw.Draw(img)

        d.text((4, 0), TICKER, fill=(255, 255, 255), font=font)
        d.text((4, 8), CURRENT, fill=self.greenORred, font=font)

        img.paste(ARROW, ((text_width_current + 7),10))
        d.text(((text_width_current+18), 8), CHANGE, fill=self.greenORred, font=font)

        text_width_change, text_height = self.get_text_dimensions(CHANGE, font)

        newWidth = text_width_current + text_width_change +30

        img = img.crop((0,0,newWidth,32)) 
        return img 

    #Stitch the logo & prices picture into one image
    def stitchImage(self, image_list):
        widths, heights = zip(*(i.size for i in image_list))
        total_width = sum(widths)
        max_height = max(heights)
        new_im = Image.new('RGB', (total_width, max_height))
        x_offset = 0
        for im in image_list:
            new_im.paste(im, (x_offset,0))
            x_offset += im.size[0]
           
        return new_im

    def resetMatrix(self):
        for x in range(self.matrix.width):
            for y in range(self.matrix.height):
                self.matrix.SetPixel(x , y , 0,0,0)
    
    
    def getCryptoImage(self):
        
        
        f = open('csv/crypto_settings.json', 'r')
        all_crypto_settings = json.load(f)
        f.close()
        
        if all_crypto_settings['title']:
            title_img = self.openImage('feature_titles/crypto.png')
            image_list = [title_img]
            image_list.append(self.blank)
        else:
            image_list = []
        
        
        
        coin_info = all_crypto_settings['symbols']
        coin_bases = list(coin_info.keys())
     
        for i, cb in enumerate(coin_bases):
            try:
                ticker, base = cb.split(',')
                current = float(coin_info[cb]["current"])
                point_change = float(coin_info[cb]["24hr_change"])
                
                percent_change = float(coin_info[cb]["percent_change"])
                
        
                
                arrow, change = self.getArrow(point_change)
                
                percent_change = str(abs(percent_change)) + '%'
                point_change = str(abs(point_change))
                current = str(current)
                
                if not all_crypto_settings['percent']:
                    percent_change = False
                if not all_crypto_settings['point']:
                    point_change = False
                   
                midFrame = self.textToImage(ticker + '(' + base + ')', current, arrow, percent_change, point_change) #IMAGE THE TEXT
                
                if all_crypto_settings['logos']:
                    try:
                        logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'crypto')
                       
                        logo = self.openImage(os.path.join(logos_path,  ticker + '.png'))
                        stitchedStock = self.stitchImage([logo,midFrame])
                    except Exception as e:
                       
                        stitchedStock = midFrame
                else:
                    stitchedStock = midFrame
                    
                image_list.append(stitchedStock)
            
                image_list.append(self.blank)
            
            except Exception as e:
                
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            

        finalDisplayImage = self.stitchImage(image_list)
        
        return finalDisplayImage
        
    def getCryptoProfessional(self):
       
        
        self.blank = Image.new('RGB', (0, 16))
        
        f = open('csv/crypto_settings.json', 'r')
        all_crypto_settings = json.load(f)
        f.close()
        
        if all_crypto_settings['title']:
            title_img = self.openImage('feature_titles/small_feature_titles/crypto.png')
            image_list = [title_img]
            image_list.append(self.blank)
        else:
            image_list = []
        
        
        
        coin_info = all_crypto_settings['symbols']
        coin_bases = list(coin_info.keys())
        
      
        
        
        for i, cb in enumerate(coin_bases):
            try:
                ticker, base = cb.split(',')
                current = float(coin_info[cb]["current"])
                change = float(coin_info[cb]["24hr_change"])
                arrow, change = self.getArrow(change, professional=True)
                
                if all_crypto_settings["percent"]: 
                    # convert percent to points
                    change = str(abs(float(coin_info[cb]['percent_change']))) + '%'
                else:
                   
                    change = str(abs(float(change)))
                
                current = str(current)
                midFrame = self.textToImageProf(ticker + '(' + base + ')', current, change, arrow, font=ImageFont.load("./fonts/6x10.pil")) #IMAGE THE TEXT
                if all_crypto_settings['logos']:
                    try:
                        logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'crypto')
                        logo = self.openImage(os.path.join(logos_path,  ticker + '.png'))
                        
                        w,h = logo.size 
                        logo=logo.resize((int(w/2), int(h/2)))
                        stitchedStock = self.stitchImage([logo,midFrame])
                    except:
                        
                        stitchedStock = midFrame
                else:
                    stitchedStock = midFrame
                image_list.append(stitchedStock)
            
                image_list.append(self.blank)
            
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
        finalDisplayImage = self.stitchImage(image_list)
        self.blank = Image.new('RGB', (10, 32))
        return finalDisplayImage
    
    def getForexImage(self):
        
        f = open('csv/forex_settings.json', 'r')
        all_forex_settings = json.load(f)
        f.close()
    
        if all_forex_settings['title']:
            title_img = self.openImage('feature_titles/forex.png')
            image_list = [title_img]
            image_list.append(self.blank)
        else:
            image_list = []
            
        forex_settings = all_forex_settings['symbols']
        
        
        symbol_bases = list(forex_settings.keys())
        
        for i, sb in enumerate(symbol_bases):
            try:
                symbol, base = sb.split(',')
                
                current = float(forex_settings[sb]['current'])
                change = float(forex_settings[sb]['24hr_change'])
                
                percent_change = str(abs(float(forex_settings[sb]['percent_change']))) +'%' 
                
               
                point_change = str(abs(change))
                
                if not all_forex_settings['percent']:
                    percent_change = False
                if not all_forex_settings['point']:
                    point_change = False
                
                arrow, change = self.getArrow(change)
                
                
                
                current = str(current)
               
                    
                midFrame = self.textToImage(base+ '(' + symbol + ')', current, arrow, percent_change, point_change) #IMAGE THE TEXT
                
                
                if all_forex_settings['logos']:
                    try: 
                        logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'currencies')
                       
                        logo = Image.open(os.path.join(logos_path,  symbol.upper() + '.png'))
                        bse = Image.open(os.path.join(logos_path,  base.upper() + '.png'))
                        
                        new_im = Image.new('RGB', (32, 32))
                        
                        
                        new_im.paste(bse, (0,10), bse.convert('RGBA'))
                        new_im.paste(logo, (10,0), logo.convert('RGBA'))
                        
                        stitchedStock = self.stitchImage([new_im, midFrame])
                        image_list.append(new_im)

                    except Exception as e:
                        print(e)
                   
                image_list.append(midFrame)
                image_list.append(self.blank)
            
            except Exception as e:
                
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
            
        finalDisplayImage = self.stitchImage(image_list)

        return finalDisplayImage
    
    def getForexProfessional(self):
        
        self.blank = Image.new('RGB', (0, 16))
        f = open('csv/forex_settings.json', 'r')
        all_forex_settings = json.load(f)
        f.close()
    
        if all_forex_settings['title']:
            title_img = self.openImage('feature_titles/small_feature_titles/forex.png')
            image_list = [title_img]
            image_list.append(self.blank)
        else:
            image_list = []
            
        forex_settings = all_forex_settings['symbols']
        
        
        symbol_bases = list(forex_settings.keys())
        
      
        for i, sb in enumerate(symbol_bases):
            try:
                symbol, base = sb.split(',')
                
                current = float(forex_settings[sb]['current'])
                change = float(forex_settings[sb]['24hr_change'])
                
                
                    
                    
                arrow, change = self.getArrow(change, professional = True)
                
                
                if all_forex_settings["percent"]: 
                    # convert percent to points
                    change = abs(float(forex_settings[sb]['percent_change']))
                    
                    change = str(change) + '%'
                else:
                    change = str(change)
                current = str(current)
                midFrame = self.textToImageProf(symbol + '(' + base + ')', current, change, arrow, font = ImageFont.load("./fonts/6x10.pil")) #IMAGE THE TEXT
                
                if all_forex_settings['logos']:
                    try: 
                        logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'currencies')
                       
                        logo = Image.open(os.path.join(logos_path,  symbol.upper() + '.png'))
                        bse = Image.open(os.path.join(logos_path,  base.upper() + '.png'))
                        
                        new_im = Image.new('RGB', (32, 32))
                        
                        
                        new_im.paste(bse, (0,10), bse.convert('RGBA'))
                        new_im.paste(logo, (10,0), logo.convert('RGBA'))
                        width, height = new_im.size
                            
                        new_im = new_im.resize((int(width/2), int(height/2)))
                        
                        stitchedStock = self.stitchImage([new_im, midFrame])
                        image_list.append(new_im)
                    
                    except Exception as e:
                        print(e)
                   
                image_list.append(midFrame)
               
                image_list.append(self.blank)
            
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            

        finalDisplayImage = self.stitchImage(image_list)
        self.blank = Image.new('RGB', (10, 32))
        return finalDisplayImage
    
    def getStockImage(self):
        
        f = open('csv/stocks_settings.json', 'r')
        all_stocks_settings = json.load(f)
        f.close()
        
        if all_stocks_settings['title']:
            title_img = self.openImage('feature_titles/stocks.png')
            image_list = [title_img]
            image_list.append(self.blank)
        else:
            image_list = []
        
        
       
        
        stock_info = all_stocks_settings['symbols']
        symbols = list(stock_info.keys())

        for i, symbol in enumerate(symbols):
            
            try:
                info = stock_info[symbol]
                
                change = float(info['change']) #TEXT
                ticker = symbol #TEXT
          
                
                arrow, change = self.getArrow(change)
                
                percent_change = '%.2f' % abs(float(info['percent_change']))  + '%'
                point_change = '%.2f' % abs(change)
                
                print(percent_change, point_change)
                
                current = '%.2f' % float(info['current']) #TEXT
         
                
                
                if not all_stocks_settings['percent']:
                    percent_change = False
                if not all_stocks_settings['point']:
                    point_change = False
                
                
                
                
                midFrame = self.textToImage(ticker, current, arrow, percent_change, point_change) #IMAGE THE TEXT
                
                if all_stocks_settings['logos']:
                    try:
                        logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'stocks')
                       
                        logo = self.openImage(os.path.join(logos_path,  ticker + '.png'))
                        stitchedStock = self.stitchImage([logo,midFrame])
                    except Exception as e:
                        print(str(e))
                        stitchedStock = midFrame
                else:
                    stitchedStock = midFrame
                
                image_list.append(stitchedStock)
                
                
                image_list.append(self.blank)
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
            
   
        finalDisplayImage = self.stitchImage(image_list)
        
        
            
        return finalDisplayImage
        
    def getStockProfessional(self):
        self.blank = Image.new('RGB', (0, 16))
        
        f = open('csv/stocks_settings.json', 'r')
        all_stocks_settings = json.load(f)
        f.close()
        
        if all_stocks_settings['title']:
            title_img = self.openImage('feature_titles/small_feature_titles/stocks.png')
            image_list = [title_img, Image.new('RGB', (5, 16))]
            image_list.append(self.blank)
        else:
            image_list = []
            
       
        stock_info = all_stocks_settings['symbols']
        symbols = list(stock_info.keys())
        
        for i, symbol in enumerate(symbols):
            
            try:
                info = stock_info[symbol]
            
                change = float(info['change'])#TEXT
                ticker = symbol #TEXT
                
                
                
                arrow, change = self.getArrow(change, professional=True)
                
                if all_stocks_settings["percent"]: 
                    change = '%.2f' % abs(float(info['percent_change'])) + '%'
                else:
                    change = '%.2f' % abs(change)
                    
                    
                current = '%.2f' % float(info['current']) #TEXT
                midFrame = self.textToImageProf(ticker, current, change, arrow, font=ImageFont.load("./fonts/6x10.pil")) #IMAGE THE TEXT
                
                if all_stocks_settings['logos']:
                    try:
                        try: #load the tiny logo 
                            logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'tiny_stocks')
                           
                            logo = Image.open(os.path.join(logos_path,  ticker + '.png'))
                            
                        except: # load the big logo and scale it
                            
                            logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'stocks')
                           
                            logo = Image.open(os.path.join(logos_path,  ticker + '.png'))
                            # half the size of the logo
                            width, height = logo.size
                            
                            logo = logo.resize((int(width/2), int(height/2)))
                        stitchedStock = self.stitchImage([logo,midFrame])
                    except Exception as e:
               
                        stitchedStock = midFrame
                else:
                    stitchedStock = midFrame
                
                image_list.append(stitchedStock)
                
                
                image_list.append(self.blank)
            
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
   
        finalDisplayImage = self.stitchImage(image_list)
        
        
        self.blank = Image.new('RGB', (10, 32))
        return finalDisplayImage
        
    def getNewsImage(self):
        
        all_settings = json.load(open('csv/news_settings.json', 'r'))
        
        if all_settings['title']:
            title_img = self.openImage('feature_titles/news.png')
            image_list = [title_img]
        else:
            image_list = []
            
        headline_font = ImageFont.load("./fonts/6x13.pil")
        source_font = ImageFont.load("./fonts/6x13.pil")
        
        headline_info = all_settings['headlines']
        
        headlines = []
        source_date_times = []
        source = []
        
        

        for i, hi in enumerate(headline_info):
            try:
                headline, source, date_time = hi
                date, time = date_time.split('T')
                time = time[:-1]
                source_date_time = source + ': ' + date + ' ' + time
                
                headline = headline.replace("^", ",")
                headline = headline.replace("’", "'")
                headline = headline.replace("‘", "'")
                headline = headline.replace('“', '"')
                headline = headline.replace('”', '"')
                headline = headline.replace('—', '-')
                headline = headline.replace('–', '-')
                headline = ''.join([h for h in headline if ord(h) < 256])
                
                lst = headline.rsplit('-', 1) #remove source name at end of headline
                headline = lst[0]
                
                headline_img = self.textImage(headline, headline_font, matrix_height = True)
                source_img = self.textImage(source_date_time, source_font, r=255, g=255, b=0, matrix_height = True)

                try:
                    logo_name = source.lower().replace(' ', '-')
                    logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
               
                    logo = Image.open(os.path.join(logos_path,  logo_name + '.png'))
                    
                except Exception as e:
                    logo_name = 'default'
                    logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
               
                    logo = Image.open(os.path.join(logos_path,  logo_name + '.png'))
                    
                

                img = Image.new('RGB', (headline_img.size[0], 32))
                img.paste(headline_img, (2, 0))
                img.paste(source_img, (2,16))
                
                img= self.stitchImage([logo,img])
                
                    
                image_list.append(img)
                image_list.append(self.blank)
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
        news_image = self.stitchImage(image_list)
        
        return news_image
        
    def getNewsProfessional(self):
        
        all_settings = json.load(open('csv/news_settings.json', 'r'))
        
        if all_settings['title']:
            title_img = self.openImage('feature_titles/small_feature_titles/news.png')
            image_list = [title_img]
        else:
            image_list = []
            
        headline_font = ImageFont.load("./fonts/6x13.pil")
        source_font = ImageFont.load("./fonts/6x13.pil")
        
        headline_info = all_settings['headlines']
        
        headlines = []
        source_date_times = []
        source = []
        

        blank = Image.new('RGB', (0, 16))
        
        for i, hi in enumerate(headline_info):
            try:
                headline, source, date_time = hi
                date, time = date_time.split('T')
                time = time[:-1]
                source_date_time = source + ': ' + date + ' ' + time
                
                headline = headline.replace("^", ",")
                headline = headline.replace("’", "'")
                headline = headline.replace("‘", "'")
                headline = headline.replace('“', '"')
                headline = headline.replace('”', '"')
                headline = headline.replace('—', '-')
                headline = headline.replace('–', '-')
                
                headline = ''.join([h for h in headline if ord(h) < 256])
                
                lst = headline.rsplit('-', 1) #remove source name at end of headline
                headline = lst[0]
                
                headline_img = self.textImage(headline, headline_font, matrix_height = True)
                source_img = self.textImage(source_date_time+ ':', source_font, r=255, g=255, b=0, matrix_height = True)
                
                
                try:
                    logo_name = source[i].lower().replace(' ', '-')
                    logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
                
                    logo = Image.open(os.path.join(logos_path,  logo_name + '.png'))
                    
                except Exception as e:
                    logo_name = 'default'
                    logos_path = os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'logos'), 'news_logos')
               
                    logo = Image.open(os.path.join(logos_path,  logo_name + '.png'))

                width, height = logo.size
                    
                logo = logo.resize((int(width/2), int(height/2)))

                img = Image.new('RGB', (headline_img.size[0]+ source_img.size[0] + logo.size[0] +5, 32))
                img.paste(headline_img, (source_img.size[0]+   logo.size[0] -5, 3))
                img.paste(source_img, (2,3))
                
                img= self.stitchImage([logo,img])
                    
          
                    
                    
                image_list.append(img)
                image_list.append(blank)
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
        news_image = self.stitchImage(image_list)
        
        return news_image
        
    def getLeagueImage(self, league=False, time = 'past'):
        
        if time in ['past', 'live']:
            filepath = 'csv/{}_games.json'.format(time)
            
        else:
            print(time)
            filepath = 'csv/upcoming_games.json'
            
            
        all_settings = json.load(open(filepath, 'r'))
        title_img = self.openImage('feature_titles/sports_'+ time + '.png')
        if all_settings['title']:
            title_img = self.openImage('feature_titles/sports_{}.png'.format(time))
            imgs = [title_img, self.blank]
        else:
            imgs = []
            
            
        leagues_info = all_settings['leagues']
        
        leagues = list(leagues_info.keys())
            
        
        for league in leagues:
            try:
            

                x_offset = 0
                img = Image.new('RGB', (10000, 32))
                league_info = leagues_info[league]
                
                
                try:
                    league_logo = Image.open('logos/sports/league_logos/{}.png'.format(league)).convert('RGB')
                    img.paste(league_logo, (x_offset,0))
                    x_offset += league_logo.size[0] +self.blank.size[0]
                except:
                    pass

                small_font = ImageFont.load("./fonts/5x7.pil")
                med_font = ImageFont.load("./fonts/7x14B.pil")
                large_font = ImageFont.load("./fonts/9x18B.pil")

                sports_info = self.readSportsCSV(league)
                print(sports_info)

                buff_size = 25

                for match in league_info:
                    strHomeTeam = match['home_team']
                    strAwayTeam = match['away_team']
                    
                    if time != 'future':
                        intHomeScore = str(match['home_score'])
                        intAwayScore = str(match['away_score'])
                    
                    dateEvent = match['date'].replace('-', '.')
                    
                    #rond = match['round']
                    
                    
                    try:
                        
                        home_logo = Image.open('logos/sports/{}/{}'.format(league, sports_info[strHomeTeam]['logo']))
                        
                    except Exception as e:
                        home_logo = self.textImage(strHomeTeam.replace(' ', '\n'), small_font, r = 255, g = 255, b = 255)
                  
                            
                    try:
           
                        away_logo = Image.open('logos/sports/{}/{}'.format(league, sports_info[strAwayTeam]['logo']))
                        
                    except Exception as e:
                        away_logo = self.textImage(strAwayTeam.replace(' ', '\n'), small_font, r = 255, g = 255, b = 255)
                     

                    date_timage = self.textImage(dateEvent, small_font, r = 255, g = 255, b = 255)
                    
                    img.paste(home_logo, (x_offset,0))
                    
                    x_offset += home_logo.size[0] + 2
                    
                    
                    if time == 'future':
                        img.paste(date_timage, (x_offset+5, 0))
                        
                        
                        h_colour = mcolors.to_rgb(sports_info[strHomeTeam]['colour'].replace(' ', ''))
                        a_colour = mcolors.to_rgb(sports_info[strAwayTeam]['colour'].replace(' ', ''))
                        
                        
                        hc_timage = self.textImage(sports_info[strHomeTeam]['code'], med_font, r = int(h_colour[0]*255),  g = int(h_colour[1]*255),  b = int(h_colour[2]*255))
                        ac_timage = self.textImage(sports_info[strAwayTeam]['code'], med_font, r = int(a_colour[0]*255),  g = int(a_colour[1]*255),  b = int(a_colour[2]*255))
                        vs_timage = self.textImage('vs', med_font, r = 255, g = 255, b = 255, h_buff = 5)
                        
                        img.paste(hc_timage, (x_offset, 9))
                        img.paste(vs_timage, (x_offset + hc_timage.size[0], 9))
                        img.paste(ac_timage, (x_offset  + hc_timage.size[0] + vs_timage.size[0], 9))
                        x_offset += max( date_timage.size[0], hc_timage.size[0] + vs_timage.size[0] + ac_timage.size[0])
                    else:
                        
                        score_image = self.textImage(intHomeScore + '-' + intAwayScore, large_font, h_buff = 5, r = 255, g = 255, b = 255)
                        
                        #vs_timage = self.textImage(sports_info[home_team]['code'] + 'vs' + sports_info[away_team]['code'], small_font, r = 255, g = 255, b = 255)
                
                        h_colour = mcolors.to_rgb(sports_info[strHomeTeam]['colour'].replace(' ', ''))
                        a_colour = mcolors.to_rgb(sports_info[strAwayTeam]['colour'].replace(' ', ''))
                        
                        hc_timage = self.textImage(sports_info[strHomeTeam]['code'], small_font, r = int(h_colour[0]*255),  g = int(h_colour[1]*255),  b = int(h_colour[2]*255))
                        ac_timage = self.textImage(sports_info[strAwayTeam]['code'], small_font, r = int(a_colour[0]*255),  g = int(a_colour[1]*255),  b = int(a_colour[2]*255))
                        vs_timage = self.textImage('vs', small_font, r = 255, g = 255, b = 255)
                        
                        if date_timage.size[0] > score_image.size[0]:
                            img.paste(date_timage, (x_offset+2, 0))
                            img.paste(hc_timage, (x_offset+6, 9))
                            img.paste(vs_timage, (x_offset+5 + hc_timage.size[0], 9))
                            img.paste(ac_timage, (x_offset+6  + hc_timage.size[0] + vs_timage.size[0], 9))
                            img.paste(score_image, (x_offset + 2 + int((date_timage.size[0] - score_image.size[0])/2), 15))
                        else:
                            
                            img.paste(date_timage, (x_offset+1+int((score_image.size[0] - date_timage.size[0] )/2), 0))
                            vs_size = hc_timage.size[0] + vs_timage.size[0] + ac_timage.size[0]
                            img.paste(hc_timage, (x_offset + 1 + int((score_image.size[0] - vs_size)/2), 9))
                            img.paste(vs_timage, (x_offset + int((score_image.size[0] - vs_size)/2) + hc_timage.size[0], 9))
                            img.paste(ac_timage, (x_offset+1 + int((score_image.size[0] - vs_size)/2) + hc_timage.size[0] + vs_timage.size[0], 9))
                            
                            img.paste(score_image, (x_offset+1, 15))
                            
                        
                        x_offset += max( date_timage.size[0]+4, hc_timage.size[0] + vs_timage.size[0] + ac_timage.size[0]+4, 2 + int(score_image.size[0]))
                        
                        #img.paste(vs_timage, (x_offset+4, 9))
                    
                    #if league == 'NHL':
                    #
                    #img.paste(round_timage, (x_offset+ 7, 8))
                    #x_offset += max(home_timage.size[0], away_timage.size[0], date_timage.size[0], round_timage.size[0], score_image.size[0])

                    img.paste(away_logo, (x_offset,0))
                    
                    x_offset += away_logo.size[0]
                    x_offset += buff_size
                img = img.crop((0,0,x_offset ,32))
                imgs.append(img)
            except Exception as e:
                
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
        
        
        
        return self.stitchImage(imgs)
            
    def getLeagueTableImage(self, league = False):
        
        
        all_settings = json.load(open('csv/league_tables.json', 'r'))
        
        leagues_info = all_settings['leagues']
        
        leagues = list(leagues_info.keys())
        
        if all_settings['title']:
                title_img = self.openImage('feature_titles/sports_team_stats.png')
                imgs = [title_img, self.blank]
        else:
            imgs = []
                
        for league in leagues:
         
            try:
                x_offset = 0
                
                img = Image.new('RGB', (10000, 32))
                
                
                league_logo = Image.open('logos/sports/league_logos/{}.png'.format(league)).convert('RGB')
                img.paste(league_logo, (x_offset,0))
                x_offset += league_logo.size[0] +self.blank.size[0]
            
                    
                    
                team_info = leagues_info[league]
                
                small_font = ImageFont.load("./fonts/5x7.pil")
                med_font = ImageFont.load("./fonts/8x13B.pil")
                large_font = ImageFont.load("./fonts/10x20.pil")
                
                       
                #if league =='NHL': # read the NHl info from the csv, prem will need this as well
                sports_info = self.readSportsCSV(league) # gets colour and symbol info etc from csv
                
                buff_size = 20
                
                for team in team_info:
               
                    try:
            
                            
                        logo = Image.open('logos/sports/{}/{}'.format(league, sports_info[team['name']]['logo']))
                        
                
                        img.paste(logo, (x_offset, 0))
                        x_offset += logo.size[0] + 2
                    except Exception as e:
                  
                        print('no logo for:', team['name'])
                        
                        
                    name_timage = self.textImage(team['name'], med_font, r = 255, g = 255, b = 0)
                    wins_timage = self.textImage('Wins:' + str(team['wins']), small_font, r = 0, g = 255, b = 0)
                    loss_timage = self.textImage('Losses:' + str(team['loss']), small_font, r = 255, g = 0, b = 0)
                    draw_timage = self.textImage('Draws:' + str(team['draw']), small_font, r = 0, g = 0, b = 255)
                    #points_timage = self.textImage('Points:' + team['points'], small_font, r = 255, g = 255, b = 255)
                    standing_timage = self.textImage('Standing:' + str(team['standing']), small_font, r = 255, g = 255, b = 255)
                    
                   
                    
                    img.paste(name_timage, (x_offset, -1))
                    img.paste(wins_timage, (x_offset, 12))
                    img.paste(loss_timage, (x_offset, 19))
                    img.paste(draw_timage, (x_offset, 26))
                    
                    x_offset += max( wins_timage.size[0], loss_timage.size[0], draw_timage.size[0])
                    #img.paste(points_timage, (x_offset, 14))
                    img.paste(standing_timage, (x_offset, 22))
                    
                    #x_offset += max(points_timage.size[0], standing_timage.size[0]) + buff_size
                    x_offset += standing_timage.size[0] + buff_size
                    
                    
                img = img.crop((0,0,x_offset ,32))
                imgs.append(img)
            except Exception as e:
                
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
                
        return self.stitchImage(imgs)
           
    def getTodayWeatherImage(self):
        all_settings = json.load(open('csv/current_weather.json', 'r'))
        
        if all_settings['title']:
            title_img = self.openImage('feature_titles/weather.png')
            imgs = [title_img, self.blank]
        else:
            imgs = []
        
        
        
        current_weathers = all_settings['locations']
        locations = list(current_weathers.keys())
        
        for i, location in enumerate(locations):
            try: 
                
                current_weather = current_weathers[location]
                small_font = ImageFont.load("./fonts/5x7.pil")
                large_font = ImageFont.load("./fonts/10x20.pil")

                location_img = self.textImage(location.upper(), small_font, r = 255, g = 255, b = 0)
                main = current_weather['main_weather']
                if main == 'Clouds':
                    main = current_weather['description']
                weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09', 
                'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
                 'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
                
                weather_dir = './logos/weather_icons'
                weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
                temp = current_weather['temp']
                feels_temp = current_weather['feels_like']
                if all_settings['temp'] == 'kelvin':
                    temp = current_weather['temp'] + 273.15
                elif all_settings['temp'] == 'fahrenheit':
                    feels_temp = current_weather['feels_like']*9/5 + 32
                    temp = current_weather['temp']*9/5 + 32
                    
                temp_img = self.textImage(str("{0:.0f}".format(temp)), large_font)
                deg_img = self.textImage('o', small_font)
                main = current_weather['main_weather']
                main_img = self.textImage(main.upper(), small_font)
                feels_img = self.textImage('Feels like:'.upper() + str("{0:.0f}".format(feels_temp)), small_font)
                min_img = self.textImage( "{0:.0f}".format(current_weather['min_temp']), small_font, r=0, g=0, b=255)
                max_img = self.textImage( "{0:.0f}".format(current_weather['max_temp']), small_font, r=255, g=0, b=0)
                hum_img = Image.open(weather_dir + '/humidity.png')
                htext_img = self.textImage(str(current_weather['humidity']) + '%', small_font)
                uv_img = Image.open(weather_dir + '/uv.png')
                utext_img = self.textImage(str(round(current_weather['uv'], 1)) , small_font)
                weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
                months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
                month = months[int(datetime.now().strftime('%m'))-1]
                date = str(int(datetime.now().strftime('%d')))
                weekday = weekdays[datetime.today().weekday()]
                date_img = self.textImage((month + ' ' + date + ',' + weekday).upper(), small_font)
                rain_img = Image.open(weather_dir + '/rain-chance.png')
                rtext_img = self.textImage(str(int(current_weather['rain_chance']*100)) + '%', small_font)
                cloud_img = Image.open(weather_dir + '/clouds.png')
                ctext_img = self.textImage(str(current_weather['clouds']) + '%', small_font)
                wind_img = Image.open(weather_dir + '/wind.png')
                w_speed = current_weather['wind_speed']*3.6
                w_unit = 'K/H'
                if all_settings["wind_speed"] == "miles/hour":
                    w_speed = current_weather['wind_speed']*2.236936
                    w_unit = 'M/H'
                wtext_img = self.textImage("{0:.0f}".format(w_speed) + w_unit, small_font)
                wdir_img = self.textImage(self.degreesToCompass(current_weather['wind_direction']).upper(), small_font)
                vis_img = Image.open(weather_dir + '/visibility.png')
                vtext_img = self.textImage(str(round(current_weather['visibility']/1000, 1)) + 'km'.upper(), small_font)
                
                
                
                '------------------------------------------'
                img = Image.new('RGB', (1000, 32))
                
                img.paste(weather_img, (5,9))
                x_offset = 5 + weather_img.size[0] + 1
                
                img.paste(main_img, (x_offset, 26))
                img.paste(temp_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2,9))
              
                img.paste(deg_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2 +  temp_img.size[0], 8))
                
                x_offset += max( main_img.size[0], temp_img.size[0] + deg_img.size[0]) 
                
                
                img.paste(min_img, (x_offset - 1, 12))
                img.paste(max_img, (x_offset - 1, 21))
                
                x_offset += max(min_img.size[0], max_img.size[0]) + 2
                img.paste(hum_img, ( x_offset, 8))
                img.paste(uv_img, ( x_offset, 22))
                
                img.paste(htext_img, (x_offset + hum_img.size[0], 10))
                img.paste(utext_img, (x_offset + uv_img.size[0], 23))
                x_offset += max(hum_img.size[0], uv_img.size[0]+2)
                x_offset += max(htext_img.size[0], utext_img.size[0]) + 6
                
                
                img.paste(rain_img, (x_offset,8))
                img.paste(cloud_img, (x_offset,20))
                img.paste(ctext_img, (x_offset + cloud_img.size[0] + 2, 22))
                img.paste(rtext_img, (x_offset + rain_img.size[0]+ 2, 10))
                x_offset += max(cloud_img.size[0], rain_img.size[0])+6
                x_offset += max(ctext_img.size[0], rtext_img.size[0])+6
                img.paste(wind_img, (x_offset,8))
                img.paste(vis_img, (x_offset,20))
                img.paste(wtext_img, (x_offset + wind_img.size[0] + 2, 10))
                img.paste(vtext_img, (x_offset + vis_img.size[0] + 2, 22))
                x_offset += wind_img.size[0] + wtext_img.size[0] + 4 
                img.paste(wdir_img, (x_offset, 10))
                
                
                
                
                
                img.paste(location_img, (5,0))
                img.paste(feels_img, (location_img.size[0] + 10, 0))
                img.paste(date_img, (location_img.size[0] + feels_img.size[0] + 15, 0))
                
                
                img = img.crop((0,0,max(x_offset +wdir_img.size[0] + 4, location_img.size[0] + feels_img.size[0] + 15 + date_img.size[0]) ,32))
                imgs.append(img)
                imgs.append(self.blank)
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
                
        
        return self.stitchImage(imgs)
    
    def getTodayWeatherProfessional(self):
        all_settings = json.load(open('csv/current_weather.json', 'r'))
        
        if all_settings['title']:
            title_img = self.openImage('feature_titles/small_feature_titles/weather.png')
            image_list = [title_img, Image.new('RGB', (3, 16))]
        else:
            image_list = []
        
        
        
        current_weathers = all_settings['locations']
        locations = list(current_weathers.keys())
        
        weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
        months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        month = months[int(datetime.now().strftime('%m'))-1]
        date = str(int(datetime.now().strftime('%d')))
        
        weekday = weekdays[datetime.today().weekday()]
        
        for i, location in enumerate(locations):
            try:

                img = Image.new('RGB', (1000, 32))
                
                
                current_weather = current_weathers[location]
                small_font = ImageFont.load("./fonts/4x6.pil")
                font = ImageFont.load("./fonts/6x10.pil")
                large_font = ImageFont.load("./fonts/10x20.pil")

                main = current_weather['main_weather']
                if main == 'Clouds':
                    main = current_weather['description']
                weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09', 
                'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
                 'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
                
                weather_dir = './logos/weather_icons'
                
                location_img = self.textImage(location.upper(), font, r = 255, g = 255, b = 0)
                
                img.paste(location_img, (5,3)) 
                x_offset = location_img.size[0] + 8
                
            
                date_img = self.textImage((month + ' ' + date + ',' + weekday).upper(), font)
                
                img.paste(date_img, (x_offset, 3))
                
                x_offset += date_img.size[0] + 2
                
                
                weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
                w, h = weather_img.size
                weather_img = weather_img.resize((int(w/2), int(h/2)))
                
                main = current_weather['main_weather']
                main_img = self.textImage(main.upper(), font)
                img.paste(main_img, (x_offset, 3))
                x_offset += main_img.size[0] + 2 
                
                img.paste(weather_img, (x_offset,3))
                
                x_offset += weather_img.size[0] + 2
                
                
               
                temp = current_weather['temp']
                if all_settings['temp'] == 'kelvin':
                    temp = current_weather['temp'] + 273.15
                elif all_settings['temp'] == 'fahrenheit':
                    temp = current_weather['temp']*9/5 + 32
                
                temp_img = self.textImage(str("{0:.0f}".format(temp)), font)
                img.paste(temp_img, (x_offset,3))
                x_offset += temp_img.size[0]-3
                
                deg_img = self.textImage('o', small_font)
            
                img.paste(deg_img, (x_offset+1, 1))
                
                x_offset += deg_img.size[0] -2

                min_img = self.textImage( "{0:.0f}".format(current_weather['min_temp']), small_font, r=0, g=0, b=255)
                img.paste(min_img, (x_offset+2, 2))
                
                max_img = self.textImage( "{0:.0f}".format(current_weather['max_temp']), small_font, r=255, g=0, b=0)
                img.paste(max_img, (x_offset+2, 8))
                
                x_offset += max_img.size[0] + 2
                
                hum_img = Image.open(weather_dir + '/humidity.png')
                htext_img = self.textImage(str(current_weather['humidity']) + '%', font)
                uv_img = Image.open(weather_dir + '/uv.png')
                utext_img = self.textImage(str(round(current_weather['uv'], 1)), font)

                
                rain_img = Image.open(weather_dir + '/rain-chance.png')
                rtext_img = self.textImage(str(int(current_weather['rain_chance']*100)) + '%', font)
                cloud_img = Image.open(weather_dir + '/clouds.png')
                ctext_img = self.textImage(str(current_weather['clouds']) + '%', font)
                wind_img = Image.open(weather_dir + '/wind.png') 
                
                w_speed = current_weather['wind_speed']*3.6
                w_unit = 'K/H'
                if all_settings["wind_speed"] == "miles/hour":
                    w_speed = current_weather['wind_speed']*2.236936
                    w_unit = 'M/H'
                    
                     
                wtext_img = self.textImage("{0:.0f}".format(wind_speed) + wind_unit, font)
                wdir_img = self.textImage(self.degreesToCompass(current_weather['wind_direction']).upper(), font)
                vis_img = Image.open(weather_dir + '/visibility.png')
                vtext_img = self.textImage(str(current_weather['visibility']/1000) + 'km', font)
                
                
                for image in [hum_img, htext_img, uv_img, utext_img,  rain_img, rtext_img, cloud_img, ctext_img, wind_img, wtext_img, wdir_img, vis_img, vtext_img]:
                    img.paste(image, (x_offset, 3))
                    x_offset += image.size[0] + 2
                
              
                
           
                img = img.crop((0,0,x_offset +image.size[0] ,16))
            
                image_list.append(img)
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
        return self.stitchImage(image_list)
        
    def getDailyWeatherImageAlt(self):
        
        
        f = open( "csv/weather_location.txt", 'r' )
        location = f.read()
        f.close()
        img = Image.new('RGB', (128, 32))
        
        current_weather = json.load(open('csv/current_weather.json', 'r'))
        
        small_font = ImageFont.load("./fonts/5x7.pil")
        extra_small_font = ImageFont.load("./fonts/4x6.pil")
        large_font = ImageFont.load("./fonts/10x20.pil")
        
        
        location_img = self.textImage(location, extra_small_font, r = 255, g = 255, b = 0)
        
        
        
        main = current_weather['main_weather']
        if main == 'Clouds':
            main = current_weather['description']
        weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09', 
        'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
         'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
        
        weather_dir = './logos/weather_icons'
        
        weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
        
        
        temp_img = self.textImage(str("{0:.0f}".format(current_weather['temp'])), large_font)
        
        
        deg_img = self.textImage('o', small_font)
        
        min_img = self.textImage( "{0:.0f}".format(current_weather['min_temp']), small_font, r=0, g=0, b=255)
        
        
        max_img = self.textImage( "{0:.0f}".format(current_weather['max_temp']), small_font, r=255, g=0, b=0)
        
        
        main = current_weather['main_weather']
        main_img = self.textImage(main, small_font)
        
        weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
        months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        month = months[int(datetime.now().strftime('%m'))]
        date = str(int(datetime.now().strftime('%d')))
        
        weekday = weekdays[datetime.today().weekday()]
        
        date_img = self.textImage(month + ' ' + date + ',' + weekday, extra_small_font)

        rain_img = Image.open(weather_dir + '/rain-chance.png')
        
        rtext_img = self.textImage(str(int(current_weather['rain_chance']*100)) + '%', extra_small_font)
        
        
        hum_img = Image.open(weather_dir + '/humidity.png')
        
        
        htext_img = self.textImage(str(current_weather['humidity']) + '%', extra_small_font)
        
        
        uv_img = Image.open(weather_dir + '/uv.png')
        
        
        utext_img = self.textImage(str(current_weather['uv']) , extra_small_font)
        
        wind_img = Image.open(weather_dir + '/wind.png')
    
        wtext_img = self.textImage(str(current_weather['wind_speed']) + 'm/s', extra_small_font)

       
        img.paste(location_img, (0,0)) 
        img.paste(weather_img, (0,12))
        img.paste(temp_img, (30,9))
        img.paste(deg_img, (50, 8))
        img.paste(min_img, (55, 10))
        img.paste(main_img, (30, 26))
        img.paste(max_img, (55, 19))
        img.paste(date_img, (location_img.size[0], 1))
        
        
        img.paste(rain_img, (75,0))
        img.paste(rtext_img, (88, 1))
        img.paste(hum_img, (102, 0))
        img.paste(htext_img, (113, 1))
        
        #img.paste(uv_img, ( 96, 0))
        #img.paste(utext_img, (109, 0))
        #img.paste(wind_img, (96,0))
        #img.paste(wtext_img, (109,0))
        
        
        
        img0 = img
        
        img = Image.new('RGB', (1000, 32))
        
        
        daily_weather = json.load(open('csv/daily_weather.json', 'r'))
        
        #img.paste(date_img, (70, 0))
        
      
        x_offset = 64
    
        for i in range(0,len(daily_weather)-1):
            
        
            weekday = weekdays[(datetime.today().weekday() + i)%7]
            
            day_img = self.textImage( weekday, small_font)
            weather = daily_weather[i]
            main = weather['main_weather']
            
            
            if main == 'Clouds':
                main = weather['description']
            
            weather_img = Image.open(weather_dir + '/small_icons/' + weather_ids[main] + '.png')
            min_img = self.textImage( "{0:.0f}".format(weather['min_temp']), small_font, r=0, g=0, b=255)
            
            
            max_img = self.textImage( "{0:.0f}".format(weather['max_temp']), small_font, r=255, g=0, b=0)
            
            img.paste(day_img, (x_offset +5, 9))
            img.paste(weather_img, (x_offset +5, 16))
            img.paste(min_img, (x_offset + 25, 10))
            img.paste(max_img, (x_offset + 25, 20))
            
            x_offset += 35
                
        img1 = img.crop((64,0,x_offset ,32))
        
        img1.save('display_images/weather.ppm')
        
        return img0, img1
        
        
    def getDailyWeatherImage(self):
        
        
        all_settings = json.load(open('csv/daily_weather.json', 'r'))
        
        if all_settings['title']:
            title_img = self.openImage('feature_titles/forecast.png')
            imgs = [title_img, self.blank]
        else:
            imgs = []
        
        
        
        daily_weathers = json.load(open('csv/daily_weather.json', 'r'))
        
        locations = list(daily_weathers['locations'].keys())
        
        for i, location in enumerate(locations):
            print(location)
            try:
                img = Image.new('RGB', (1000, 32))
                
                
                daily_weather = daily_weathers['locations'][location]
                
                small_font = ImageFont.load("./fonts/5x7.pil")
                extra_small_font = ImageFont.load("./fonts/4x6.pil")
                large_font = ImageFont.load("./fonts/10x20.pil")
                
                
                location_img = self.textImage(location.upper(), extra_small_font, r = 255, g = 255, b = 0)
                main = daily_weather[0]['main_weather']
                if main == 'Clouds':
                    main = daily_weather[0]['description']
                weather_ids = {'Clear': '01', 'few clouds': '02', 'scattered clouds': '03', 'broken clouds':'04', 'overcast clouds':'04', 'Drizzle':'09', 
                'Rain':'10', 'Thunderstorm':'11', 'Snow':'13', 'Mist': '50', 'Smoke': '50', 'Haze': '50', 'Dust': '50', 'Fog': '50',
                 'Sand': '50', 'Ash': '50', 'Squall': '50', 'Tornado': '50'}
                
                weather_dir = './logos/weather_icons'
                
                weather_img = Image.open(weather_dir + '/weather_type_icons/' + weather_ids[main] + '.png')
                
                
                temp = daily_weather[0]['temp']
                min_temp = daily_weather[0]['min_temp']
                max_temp = daily_weather[0]['max_temp']
                
                if daily_weathers['temp'] == 'kelvin':
                    temp = daily_weather[0]['temp'] + 273.15
                    min_temp = daily_weather[0]['min_temp'] + 273.15
                    max_temp = daily_weather[0]['max_temp'] + 273.15
                elif daily_weathers['temp'] == 'fahrenheit':
                    temp = daily_weather[0]['temp']*9/5 + 32
                    min_temp = daily_weather[0]['min_temp']*9/5 + 32
                    max_temp = daily_weather[0]['max_temp']*9/5 + 32
                    
                    
                temp_img = self.textImage(str("{0:.0f}".format(temp)), large_font)
                deg_img = self.textImage('o', small_font)
                
                min_img = self.textImage( "{0:.0f}".format(min_temp), small_font, r=0, g=0, b=255)
                max_img = self.textImage( "{0:.0f}".format(max_temp), small_font, r=255, g=0, b=0)
                main = daily_weather[0]['main_weather']
                main_img = self.textImage(main.upper(), small_font)
                
                weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
                months =['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
            
                month = months[int(datetime.now().strftime('%m'))-1]
                date = str(int(datetime.now().strftime('%d')))
                weekday = weekdays[datetime.today().weekday()]
                date_img = self.textImage((month + ' ' + date + ',' + weekday).upper(), extra_small_font)
                
                
                rain_img = Image.open(weather_dir + '/rain-chance.png')
                rtext_img = self.textImage(str(int(daily_weather[0]['rain_chance']*100)) + '%', extra_small_font)
                hum_img = Image.open(weather_dir + '/humidity.png') 
                htext_img = self.textImage(str(daily_weather[0]['humidity']) + '%', extra_small_font)
                wind_img = Image.open(weather_dir + '/wind.png')
                wtext_img = self.textImage(str(daily_weather[0]['wind_speed']) + 'm/s'.upper(), extra_small_font)
                uv_img = Image.open(weather_dir + '/uv.png')
                utext_img = self.textImage(str(round(daily_weather[0]['uv'], 1)) , small_font)
                cloud_img = Image.open(weather_dir + '/clouds.png')
                ctext_img = self.textImage(str(daily_weather[0]['clouds']) + '%', small_font)
                wind_img = Image.open(weather_dir + '/wind.png')
                
                
                w_speed = daily_weather[0]['wind_speed']*3.6
                w_unit = 'K/H'
                if daily_weathers['wind_speed'] == "miles/hour":
                    w_speed = daily_weather[0]['wind_speed']*2.236936
                    w_unit = 'M/H'
                    
                    
                wtext_img = self.textImage("{0:.0f}".format(w_speed) + w_unit, small_font)
                wdir_img = self.textImage(self.degreesToCompass(daily_weather[0]['wind_direction']), small_font)
                vis_img = Image.open(weather_dir + '/visibility.png')
                vtext_img = self.textImage(str(round(daily_weather[0]['visibility']/1000, 1)) + 'km'.upper(), small_font)
                
                
                img.paste(location_img, (0,0)) 
                
                x_offset = location_img.size[0]+2 
                
                
                img.paste(weather_img, (5,9))
                x_offset = 5 + weather_img.size[0] + 1
                
                img.paste(main_img, (x_offset, 26))
                img.paste(temp_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2,9))
              
                img.paste(deg_img, (x_offset + main_img.size[0]//2 - temp_img.size[0]//2 +  temp_img.size[0], 8))
                
                x_offset += max( main_img.size[0], temp_img.size[0] + deg_img.size[0]) 
                
                
                img.paste(min_img, (x_offset - 1, 12))
                img.paste(max_img, (x_offset - 1, 21))
                
                x_offset += max(min_img.size[0], max_img.size[0]) + 2
                
                img.paste(date_img, (x_offset, 1))
                x_offset += date_img.size[0]+2 
                
                img.paste(rain_img, (x_offset,0))
                x_offset += rain_img.size[0]+2 
                img.paste(rtext_img, (x_offset, 1))
                x_offset += rtext_img.size[0]+2 
                
                img.paste(hum_img, (x_offset, 0))
                x_offset += hum_img.size[0]+2 
                img.paste(htext_img, (x_offset, 1))
                x_offset+= htext_img.size[0]+2 
                
                img.paste(uv_img, ( x_offset, 0))
                x_offset += uv_img.size[0]+2 
                img.paste(utext_img, (x_offset, 1))
                x_offset += utext_img.size[0]+2 
                
                img.paste(cloud_img, (x_offset,0))
                x_offset += cloud_img.size[0]+2 
                img.paste(ctext_img, (x_offset, 1))
                x_offset += ctext_img.size[0]+2 
                
                img.paste(wind_img, (x_offset,0))
                x_offset += wind_img.size[0]+2 
                img.paste(wtext_img, (x_offset, 1))
                x_offset += wtext_img.size[0]+2 
                img.paste(wdir_img, (x_offset, 1))
                x_offset+= wdir_img.size[0]+2 
                
                img.paste(vis_img, (x_offset,0))
                x_offset+= vis_img.size[0]+2 
                img.paste(vtext_img, (x_offset, 1))
                x_offset += vtext_img.size[0] +2 
                
                crop_x = x_offset
                #img.paste(uv_img, ( 96, 0))
                #img.paste(utext_img, (109, 0))
                #img.paste(wind_img, (96,0))
                #img.paste(wtext_img, (109,0))
                #img.paste(date_img, (70, 0))
                x_offset = 70
            
                for i in range(1,len(daily_weather)-1):
                    weekday = weekdays[(datetime.today().weekday() + i)%7]
                    
                    day_img = self.textImage( weekday.upper(), small_font)
                    weather = daily_weather[i]
                    main = weather['main_weather']
                    
                    
                    if main == 'Clouds':
                        main = weather['description']
                        
                        
                        
                        min_temp = weather['min_temp']
                        max_temp = weather['max_temp']
                        
                        if daily_weathers['temp'] == 'kelvin':
                       
                            min_temp = weather['min_temp'] + 273.15
                            max_temp = weather['max_temp'] + 273.15
                        elif daily_weathers['temp'] == 'fahrenheit':
                            
                            min_temp = weather['min_temp']*9/5 + 32
                            max_temp = weather['max_temp']*9/5 + 32
                    
                    weather_img = Image.open(weather_dir + '/small_icons/' + weather_ids[main] + '.png')
                    min_img = self.textImage( "{0:.0f}".format(min_temp), small_font, r=0, g=0, b=255)
                    
                    
                    max_img = self.textImage( "{0:.0f}".format(max_temp), small_font, r=255, g=0, b=0)
                    
                    img.paste(day_img, (x_offset +5, 9))
                    img.paste(weather_img, (x_offset +5, 16))
                    img.paste(min_img, (x_offset + 25, 10))
                    img.paste(max_img, (x_offset + 25, 18))
                    
                    x_offset += 43
                        
                img1 = img.crop((0,0,max(x_offset, crop_x) ,32))
                imgs.append(img1)
                imgs.append(self.blank)
                # add the image text 
            except Exception as e:
                print(str(e))
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
        
        
        
        return self.stitchImage(imgs)
    
        
    def readSportsCSV(self, league):
       
        team_info = {}
        f = open('csv/sports/{}/team_info.csv'.format(league), 'r')
        CSV = csv.reader(f)
        next(CSV)
        for row in CSV:
           
            team_info[row[0]] = {}
            team_info[row[0]]['id'] = row[1]
            team_info[row[0]]['code'] = row[2]
            team_info[row[0]]['logo'] = row[4]
            team_info[row[0]]['colour'] = row[3]
        f.close()
        return team_info
            
    def displayDailyWeatherAlt(self):
        img0, img1 = self.getDailyWeatherImageAlt()
        #img = stock_ticker.getTodayWeatherImage()
        
        
        while True:
            
            self.setImage(img0, offset_x = 0, offset_y = 0)
            image = img1
            
            img_width, img_height = image.size
        
            offset_x = 64
            offset_y = 0

            while offset_x > 64-img_width:
                offset_x -= 1
                
               
                self.setImage(image, offset_x = offset_x, offset_y = offset_y, min_x = 64, min_y = 9)
                if offset_x + img_width < self.matrix.width: # if the image is ending
                    self.setImage(image, offset_x = offset_x + img_width, offset_y = offset_y, min_x = 64, min_y = 9)
                
              
                    
                
                try:
                    msg = getInput()
                    if msg == 'K':
                        self.resetMatrix()
                        return True
                      
                
                    self.process_msg(msg)
                except KeyboardInterrupt:
                    sys.stdout.flush()
                    pass
                        
                time.sleep(self.delay*1.1)
    
        
        
    def getUserImages(self):
        
        
        
        f = open('csv/image_settings.json', 'r')
        all_settings = json.load(f)
        f.close()
        
        imgs = []
        for ind,image in enumerate(all_settings['images']):
        
            try:
                img = self.openImage(os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'user_uploads'), image))
                print(img)
                img.thumbnail((99999, 32))
                print(img)
                if all_settings['title'] and ind == 0:
                    title_img = self.openImage('feature_titles/images.png')
                    imgs.append(self.stitchImage([title_img, img]))
            
                else:
                    imgs.append(img)
                
            except Exception as e:
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
                
            
        
        return imgs
        
    def getUserGIFs(self):
        f = open('csv/GIF_settings.json', 'r')
        all_settings = json.load(f)
        f.close()
        
        GIFs = []
        
        for ind,fle in enumerate(all_settings['images']):
            
            try:
                GIF = Image.open(os.path.join(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'user_uploads'), fle))
                frames = []
                
                if ind == 0 and all_settings['title']:
                    
                    title_img = self.openImage('feature_titles/gifs.png')
            
                    for i, frame in enumerate(ImageSequence.Iterator(GIF)):
                        frame = frame.convert('RGB')
                        frame.thumbnail((128, 32))
                        
                        f = self.stitchImage([title_img, frame])
                        frames.append(f)
                    
                else:

                    for i, frame in enumerate(ImageSequence.Iterator(GIF)):
                        
                        frame = frame.convert('RGB')
                        frame.thumbnail((128, 32))
                        
                        #frame = frame.resize((99999, 32))
                        f = self.stitchImage([frame])
                        frames.append(f)
                    
                
                frames[0].save('./display_images/working_gif{}.gif'.format(str(ind)), save_all=True, append_images=frames[1:], loop=0, optimize = False)
                GIF = Image.open('./display_images/working_gif{}.gif'.format(str(ind)))
                GIFs.append(GIF)
                
                 
            except Exception as e:
                print(str(e))
                exc_type, exc_obj, exc_tb = sys.exc_info()
                fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
                self.logf.write(str(e))
                self.logf.write('. file: ' + fname)
                self.logf.write('. line: ' +  str(exc_tb.tb_lineno))
                self.logf.write('. type: ' +  str(exc_type))
                self.logf.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))
            
       
        
        #below code stitches title and GIF together
        '''
        frames = []
       
        for i, frame in enumerate(ImageSequence.Iterator(gif)):
            
            if all_settings['title']:
                f = self.stitchImage([title_img, frame])
            else:
                f = self.stitchImage([frame])
            frames.append(f)
            
        
        frames[0].save('./display_images/Custom GIFs.gif', save_all=True, append_images=frames[1:], loop=0, optimize = False)
        '''
        
        return GIFs
        
    def displayStocks(self):
        
        self.scrollImageTransition(['final.ppm', 'final.ppm'], offset_x = 0, offset_y = 0)
        
    def displayProfessional(self):
        forex = self.getForexProfessional()
        crypto = self.getCryptoProfessional()
        news = self.getNewsProfessional()
        stock = self.getStockProfessional()
        weather = self.getTodayWeatherProfessional()
        
        x_offset = 0
        news.paste(weather, (x_offset, 16))
        x_offset += weather.size[0]
        news.paste(crypto, (x_offset, 16))
        x_offset += crypto.size[0]
        news.paste(stock, (x_offset, 16))
        x_offset += stock.size[0]
        news.paste(forex, (x_offset, 16))
        x_offset += forex.size[0]
        self.double_buffer = self.matrix.CreateFrameCanvas()
        while True:
            kill = stock_ticker.scrollImage(news, offset_x = 128)
            
            if kill:
                break
                
    

    def process_msg(self, msg):
        
        if msg == 'S': # stocks
            self.scrollFunctionsAnimated(['stocks', 'stocks'], animation = 'traditional')
            
        elif msg == 'C': # crypto
            self.scrollFunctionsAnimated(['crypto', 'crypto'], animation = 'traditional')
        
        elif msg == 'F': # forex
            self.scrollFunctionsAnimated(['forex', 'forex'], animation = 'traditional')
            
        elif msg == 'N': #news
            self.scrollFunctionsAnimated(['news', 'news'], animation = 'traditional')
            
        # speed settings
        elif msg == 's':
            self.delay = 0.03
  
        elif msg == 'm':
            self.delay = 0.02
 
        elif msg == 'f':
            self.delay = 0.01
        
        
        elif msg in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']: # birghtness ettings
      
            self.brightness =  (float(msg)+1)*10
            
            self.matrix.brightness = self.brightness
        
        
        elif msg == 'T':# text
            
            self.scrollFunctionsAnimated(['text', 'text'], animation = 'traditional')
            
        elif msg == 'I': # image
            
            self.scrollFunctionsAnimated(['display_image', 'display_image'], animation = 'traditional')
            
        elif msg == 'G': # gif
          
            self.scrollFunctionsAnimated(['display_gif', 'display_gif'], animation = 'traditional')
        
        elif msg == 'W': # weather
            self.scrollFunctionsAnimated(['today_weather', 'today_weather'], animation = 'traditional')
            
        elif msg == 'D': # daily weather
            self.scrollFunctionsAnimated(['daily_weather', 'daily_weather'],animation = 'traditional')
            
        elif msg == 'P': # past league
            self.scrollFunctionsAnimated(['past_games', 'past_games'],animation = 'traditional')
        
        elif msg == 'l': # future league
            self.scrollFunctionsAnimated(['future_games', 'future_games'],animation = 'traditional')
            
        elif msg == 'L': # live game 
            self.scrollFunctionsAnimated(['live_games', 'live_games'],animation = 'traditional')
            
        elif msg == 't': #legue tble
            self.scrollFunctionsAnimated(['league_table', 'league_table'],animation = 'traditional')
            
        elif msg == 'A': #everything
  
            #userSettings = ['display_gif', 'text', 'display_image', 'stocks', 'crypto', 'forex', 'today_weather', 'daily_weather', 'league_table', 'league_games', 'news'] # these wil be read from csv, just for demo
            #userSettings = [ 'daily_weather']
            #userSettings = ['crypto', 'stocks'] # these wil be read from csv, just for demo
            #userSettings = [ 'display_image',  'news'] # these wil be read from csv, just for demo
            userSettings = json.load(open('csv/display_settings.json'))
            if 'Professional'==userSettings[0] and len(userSettings[1][0])>0 and len(userSettings[1][1])>0: #if professional display
                self.scrollProfessionalAnimated(userSettings[1])
            elif len(userSettings[1][0])>0 and 'Standard'==userSettings[0]:
                self.scrollFunctionsAnimated(userSettings[1][0], animation = 'down')
            
        elif msg == 'b':
            userSettings = json.load(open('csv/display_settings.json'))
            
            self.scrollProfessionalAnimated(userSettings)
            #self.displayProfessional()
        
        elif msg == '+':
            stock_ticker.scrollMultiple()
            
        elif msg == 'K': # kill
            self.resetMatrix()
        
        elif msg =='-':
            self.run_intro_screen()
        
        elif msg == '*':
            #
            #
            start_GIF = Image.open('./logos/startup_logo1.gif')
            self.displayGIF(start_GIF, delay = 0.02, repeat = False)
            
            #stock_ticker.setImage(start_image)
            time.sleep(2)
            self.resetMatrix()
        


    def run_intro_screen(self):
        dct = {"feature": "Custom Messages", "speed": "Medium", "animation": "Down", "title": False, "messages": [{"name": "welcome", "text": "Welcome to Fintic!", "text_colour": "White", "size": "Large", "background_colour": "Black"}, {"name": "get_started", "text": "To get started, connect your device to the \"Fintic Hotspot\" and access \"fintic.local:1024\" on your web browser. You can connect your ticker to Wi-Fi there.", "text_colour": "White", "size": "Small", "background_colour": "Black"}]}
        json.dump(dct, open('csv/message_settings.json', 'w'))
        self.scrollFunctionsAnimated(['Custom Messages'], repeat = True)
    
if __name__ == '__main__':

    with open('log.txt', "a") as log:
        try:
            stock_ticker = StockTicker()
            stock_ticker.logf = log
            

            
            #stock_ticker.getLeagueImage('NHL', 'future')
            #stock_ticker.getCryptoImage()
        
            #
            
            #stock_ticker.process_msg('*')
            #time.sleep(8)
            
            #stock_ticker.process_msg('-')
            #stock_ticker.process_msg('W')
            #stock_ticker.process_msg('A')
            
            
            
            while True:
                msg = getInput()
                stock_ticker.process_msg(msg)
        except Exception as e:
            
            exc_type, exc_obj, exc_tb = sys.exc_info()
            fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
            log.write(str(e))
            log.write('. file: ' + fname)
            log.write('. line: ' +  str(exc_tb.tb_lineno))
            log.write('. type: ' +  str(exc_type))
            log.write('\n ' + "".join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])))