import math
import matplotlib.pyplot as plt
from .Generaldistribution import Distribution

class Gaussian(Distribution):
    """ Gaussian distribution class for calculating and visualizing
    a Gaussain distribution.
    
    Attributes:
        mean (float) representing the mean value of the distribution.
        stdev (float) representing the standard deviation of the distribution.
        data_list (list of floats) a list of floats extracted from the
        data file.
    """
    
    def __init__(self, mu=0, sigma=1):
        
        Distribution.__init__(self, mu, sigma)
        
    def calculate_mean(self):
        
        """ Function to calculate the mean of the data set.
        Args: 
            None
        Returns:
            float: mean of the data set
        """
        avg = 1.0 * sum(self.data)/len(self.data)
        self.mean = avg
        return self.mean
    
    def calculate_stdev(self, sample=True):
        
        """ Function to calculate the standard deviation of the data set.
        Args:
            sample (bool): whether the data represents a sample or
            population.
        Retruns:
            float: standard deviation of the data set.
        """
        
        if sample:
            n = len(self.data) - 1
        else:
            n = len(self.data)
            
        sigma = 0
        for d in self.data:
            sigma += (d - self.mean)**2
            
        sigma = math.sqrt(sigma/n)
        self.stdev = sigma
        return self.stdev
        
    def read_data_file(self, file_name, sample=True):
        
        """ Function to read in data from a txt file. The txt file should 
        have one number (float) per line. The numbers are stored in the
        data attribute.
        After reading in the file, the mean and standard deviation 
        are calculated.
        Args:
            file_name (string): name of a file to read from
            sample (bool): if data corresponds to sample or population
            
        Returns:
            None
        """
        with open(file_name) as file:
            data_list = []
            line = file.readline()
            while line:
                data_list.append(int(line))
                line = file.readline()
                
        file.close()
        self.data = data_list
        self.mean = self.calculate_mean()
        self.stdev = self.calculate_stdev(sample)

    def plot_histogram(self):
        """
        Function to output a histogram of the instance variable data
        using matplotlib pyplot library.
        Args: 
            None

        Returns:
            None
        """
        plt.hist(self.data)
        plt.xlabel('data')
        plt.ylabel('count')
        plt.title('Histogram of Data')
        plt.show()
        
    def pdf(self, x):
        """
        Probability density function calculator for the gaussian 
        distribution.

        Parameters
        ----------
        x : float
            point for calculating the probability density function.

        Returns
        -------
        float: probability density function output

        """
        
        return (1.0/(self.stdev*math.sqrt(2*math.pi)) * 
                math.exp(-0.5*((x-self.mean)/self.stdev)**2))
    
    def plot_histogram_pdf(self, n_spaces=50):
        """
        Function to plot the normalized histogram of the data and a plot
        of the probability density function along the same range.

        Parameters
        ----------
        n_spaces : int, optional
            number of data points. The default is 50.

        Returns
        -------
        list: x values for the pdf plot
        list: y values for the pdf plot

        """
        
        mu = self.mean
        sigma = self.stdev
        
        x_min = min(self.data)
        x_max = max(self.data)
        
        x = []
        y = []
        # calculate the interval between x values
        interval = 1.0 * (x_max - x_min)/n_spaces
        
        for i in range(n_spaces):
            tmp = x_min + i*interval
            x.append(tmp)
            y.append(self.pdf(tmp))
            
        figure, axes = plt.subplots(2, sharex=True)
        axes[0].hist(self.data, density=True)
        axes[0].set_title('Normed Histogram of Data')
        axes[0].set_ylabel('Density')
        
        axes[1].plot(x, y)
        axes[1].set_title('Normal Distribution for {} sample mean and {}\
                        sample standard deviation'.format(mu, sigma))
        axes[1].set_ylabel('Density')
        plt.show()
        
        return x, y
            
    def __add__(self, other):
        """
        Function to add together two Gaussian distributions.

        Parameters
        ----------
        other : Gaussian
            Gaussian instance.

        Returns
        -------
        Gaussian: Gaussian distribution

        """
        result = Gaussian()
        result.mean = self.mean + other.mean
        result.stdev = math.sqrt(self.stdev**2 + other.stdev**2)
        
        return result
    
    def __repr__(self):
        """
        Function to output the characteristics of the Gaussian instance.

        Returns
        -------
        string: characteristics of the Gaussian

        """
        return "mean {}, standard deviation {}".format(self.mean, self.stdev)
            
            
            
            
