class ReportElementValidator(ReportElement, object):
    """
    Class for setting permission
    """
    def __init__(self):
        #super(ReportElementValidator, self).__init__(False)
        super(ReportElementValidator, self).__init__('normal', None)


    def init(self, id):
        
        # init element
        super(ReportElementValidator, self).init(id)
        self._date_unformatter = DateUnformat()
        
        # do not save instances
        self._data['report_save_historical_instances_ind'] = 'N'
        # json file operation wrapper
        self._jfile = JFileValidator(self._path, self._id, self._data)
        self._instance_save_path = "%s%s/validation/" % (self._path, self._id)
        
        #get validation settings from valid.json generated by editor
        self.validation_data = self._jfile.get_validation_data()
        
        self._meas_interval = None
        
        if self.validation_data['measurement_interval_id']:
            res = self._db.Query("""SELECT interval_unit
                                FROM measurement_interval
                        WHERE 
                            measurement_interval_id =%s""",(self.validation_data['measurement_interval_id']))
            if res:
                self._meas_interval = self._db.record[0]['interval_unit']
                
        
        self.validation_data['data_fetch_command'] = self.validation_data['data_fetch_command'].strip().replace('\r\n','\n')
        if self.validation_data['source_database_connection_id']:
            self._data['source_database_connection_id'] = int(self.validation_data['source_database_connection_id'])
        else:
            self._data['source_database_connection_id'] = 0
            
        self._data['data_fetch_command'] = self.validation_data['data_fetch_command']
        self._data['data_fetch_method'] = self.validation_data['data_fetch_method']
        
        if self.validation_data['web_service_credentials_id']:
            self._data['web_service_credentials_id'] = int(self.validation_data['web_service_credentials_id'])
        else:
            self._data['web_service_credentials_id'] = 0
        
        if self.validation_data['measurement_interval_id']:
            self._data['measurement_interval_id'] = int(self.validation_data['measurement_interval_id'])
        else:
            self._data['measurement_interval_id'] = 0
            
        
        # set report segment -d
        if self.validation_data['segment_id'] and int(self.validation_data['segment_id']):
            self._data['segment_id'] = int(self.validation_data['segment_id'])
        else:
            self._data['segment_id'] = 0        
        
        # get segment data
        self._segment = self._get_segment()
        self._segment_values = self._get_segment_values()
        
        # get validation segment value id and set it as active
        if self.validation_data['segment_value_id'] and int(self.validation_data['segment_value_id']):
            segment_value_id = int(self.validation_data['segment_value_id'])
        else:
            segment_value_id = 0
        
        # get check current segment value to be in report segments
        if segment_value_id and self._segment and any(segment['segment_value_id'] == segment_value_id for segment in self._segment_values):
            self._segment_value = list(segment for segment in self._segment_values if segment['segment_value_id'] == segment_value_id)[0]
        elif self._segment_values and self._segment:
            raise Exception("segment_value_id does not match segment_id")
        else:
            self._segment_value = list()
        
        if self._segment_value:
            self._segment_value_id = self._segment_value['segment_value_id']
        else: 
            self._segment_value_id = 0
        
        self._jfile.set_segment_value(self._segment_value)
        self._jfile.set_segment(self._segment)
    
    def _check_pre_saved_settings(self, fetch_settings):
        if fetch_settings and \
                fetch_settings['sql'] and \
                fetch_settings['sql'] == self._data['data_fetch_command'] and \
                fetch_settings['source_database_connection_id'] == self._data['source_database_connection_id'] and \
                fetch_settings['segment_id'] == self._data['segment_id']:
            return True
        return False
    def get_saved_instance(self):
        """
        get clear data for building instance
        """
        # data built by generator. it's actual data
        generation_fetch_settings = self._jfile.get_generation_fetch_settings()
                
        # data built by last validation
        validation_fetch_settings = self._jfile.get_validation_fetch_settings()
        
        # data built by last validation which was saved
        last_validation_fetch_settings = self._jfile.get_last_validation_fetch_settings()
        
        pre_saved_info = list()

        data = {'instance': None, 'meas_time': None}
        
        meas_time = None
        if self.validation_data['measurement_time']:
            meas_time = self._date_unformatter.unformat(self.validation_data['measurement_time'])
            if not meas_time:
                raise Exception("Incorrect measurement_time date format.")
        
        
        if self._check_pre_saved_settings(generation_fetch_settings):
            #print 'take generated'
            if meas_time:
                res = self._db.Query("""SELECT report_data_set_instance_id
                            FROM report_data_set_instance
                        WHERE
                            `element_id`=%s
                            AND segment_value_id = %s
                            AND measurement_time = %s
                        ORDER BY measurement_time DESC
                        LIMIT 0, 1""",(self._id, self._segment_value_id, meas_time))
                if res:
                    #print 'has meas time'
                    data_set_instance = self._db.record[0]
                    generation_fetch_settings['saved_data'] = self._jfile.get_generated_dataset_instance(data_set_instance['report_data_set_instance_id'])
                else:
                    #print 'not has'
                    generation_fetch_settings['saved_data'] = None
            else:
                generation_fetch_settings['saved_data'] = self._jfile.get_generated_dataset()
            generation_fetch_settings['source'] = 'generated'
            pre_saved_info.append(generation_fetch_settings)
        
        if self._check_pre_saved_settings(validation_fetch_settings):
            #print 'take validated'
            validation_fetch_settings['saved_data'] = self._jfile.get_validated_dataset()
            validation_fetch_settings['source'] = 'validated'
            pre_saved_info.append(validation_fetch_settings)
        
        if self._check_pre_saved_settings(last_validation_fetch_settings):
            #print 'take last saved validated'
            last_validation_fetch_settings['saved_data'] = self._jfile.get_last_validated_dataset()
            last_validation_fetch_settings['source'] = 'last_saved'
            pre_saved_info.append(last_validation_fetch_settings)
        
        # no validated query at all
        if not pre_saved_info:
            raise Exception("Please validate query first")
         
        # get pre-saved items with data 
        pre_saved_info_with_data = [pre_saved for pre_saved in pre_saved_info if pre_saved['saved_data']]
        
        # sort by generation time
        pre_saved_info_with_data.sort(key=lambda item: item['saved_data']['generation_time'], reverse = True)
        
        # check validation measurement time
        if self._data['data_fetch_method'] == 'sql':
            if self.validation_data['measurement_time']:
                #print 'meas time specified'
                # is measurement time is specified take only exact data
                pre_saved_info_with_data = [pre_saved for pre_saved in pre_saved_info_with_data if self._date_unformatter.unformat(pre_saved['saved_data']['meas_time']) == meas_time]
                #print 'pre_saved_info_with_data', len(pre_saved_info_with_data)
            else:
                # is no measurement time take only actual data
                #print 'meas time not specified'
    
                # check if generated data exists
                """
                pre_saved_info_generated = [pre_saved for pre_saved in pre_saved_info_with_data if pre_saved['source'] == 'generated']
                if pre_saved_info_generated:
                    #print 'use actual generated data'
                    # use generated data as it's actual 
                    pre_saved_info_with_data = pre_saved_info_generated
                
                else:
                """
                if True:
                    #print 'use filter to detect actual data'
                    # filter actual data
                    expired_date = None
                    
                    if self._data['max_time_before_expired_sec']:
                        #print 'use meas interval', self._data['max_time_before_expired_sec']
                        expired_date = datetime.datetime.now() - datetime.timedelta(seconds = self._data['max_time_before_expired_sec'])
                    elif self._meas_interval:
                        #print 'use meas interval', self._meas_interval
                        if self._meas_interval == 'minute':
                            expired_date = datetime.datetime.now() - datetime.timedelta(minutes = 10)
                        elif self._meas_interval == 'hour':
                            expired_date = datetime.datetime.now() - datetime.timedelta(hours = 1)
                        elif self._meas_interval == 'day':
                            expired_date = datetime.datetime.now() - datetime.timedelta(days = 1)
                        elif self._meas_interval == 'week':
                            expired_date = datetime.datetime.now() - datetime.timedelta(weeks = 1)
                        elif self._meas_interval == 'month':
                            expired_date = datetime.datetime.now() - datetime.timedelta(days = 30)
                        elif self._meas_interval == 'quarter':
                            expired_date = datetime.datetime.now() - datetime.timedelta(days = 90)
                        elif self._meas_interval == 'year':
                            expired_date = datetime.datetime.now() - datetime.timedelta(days = 365)
                        else:
                            expired_date = None
                    #print expired_date
                    if expired_date:
                        pre_saved_info_with_data = [pre_saved for pre_saved in pre_saved_info_with_data if self._date_unformatter.unformat(pre_saved['saved_data']['generation_time']) >= expired_date]
        
        if pre_saved_info_with_data:
            # if pre-saved data exists
            self._outer_conn = self._get_outer_connection()
            data['instance'] = self._outer_conn.parse_collected_data(simplejson.loads(pre_saved_info_with_data[0]['saved_data']['instance']))
            
            instance, meas_time = self._fetch_data_from_source()
            data['meas_time'] = self._date_unformatter.unformat(pre_saved_info_with_data[0]['saved_data']['meas_time'])#datetime.datetime.strptime(data['meas_time'], '%Y-%m-%d %H:%M:%S')
        else:
            # no actual pre-saved data, let's fetch it
            instance, meas_time = self._fetch_data_from_source()
            
            
            data['instance'] = instance
            data['meas_time'] = meas_time
             
        """
        #check generation sql to be equal current validation sql
        if not data['instance'] and \
                generation_fetch_settings and \
                generation_fetch_settings['sql'] and \
                generation_fetch_settings['sql'] == self.validation_data['data_fetch_command']:
            saved_data = self._jfile.get_generated_dataset()
            if saved_data:
                data = saved_data
        
        #check last validation sql to be equal current validation sql
        if not data['instance'] and \
                validation_fetch_settings and \
                validation_fetch_settings['sql'] and \
                validation_fetch_settings['sql'] == self.validation_data['data_fetch_command']:
            saved_data = self._jfile.get_validated_dataset()
            if saved_data:
                data = saved_data
                
        #check last saved validation sql to be equal current validation sql
        if not data['instance'] and \
                last_validation_fetch_settings and \
                last_validation_fetch_settings['sql'] and \
                last_validation_fetch_settings['sql'] == self.validation_data['data_fetch_command']:
            saved_data = self._jfile.get_last_validated_dataset()
            if saved_data:
                data = saved_data
        
        # no data found get by the same sql query as current validation sql.
        # raise exception - sql query must be validated
        if data['instance'] is None:
            raise Exception("Please validate query first")
        """
        
        return data['instance'], data['meas_time']        
    
    def report_generation(self, id1):
        """
        generate all enabled report elements: dataset, pivots, charts
        """
        # get instance
        instance, meas_time = self.get_saved_instance()
        self._jfile.set_meas_time(meas_time)
        
        # create dataset instance
        data_set_instance = self._process_instance(instance, meas_time, update_columns = False, write_clear_headers = True, segment_value = self._segment_value)
        
        fetched_rows = len(instance['data'])
        
        #prepare data for charts
        all_data = dict()
        all_data[0] = data_set_instance.get_formatted_header_rows()
                                
        # create all pivots
        for pivot in self._pivots:
            #data_set_pivot_instance = self._process_pivot(pivot, data_set_instance, self._segment_value)
            data_set_pivot_instance = self._process_pivot(pivot, data_set_instance)
            all_data[pivot['report_data_set_pivot_id']] = data_set_pivot_instance.get_formatted_header_rows()
        
        # create all charts
        chart_gen = ChartGenerator()
        chart_gen.report_charts(self._id, self._segment_value_id, meas_time, 0, all_data, self._jfile, chart_id = 0)
        self._make_meta()
        return fetched_rows
  
    
    
    def data_generation(self, id1):
        """
        generate dataset
        """
        # get instance
        instance, meas_time = self.get_saved_instance()
        
        # create dataset instance
        self._process_instance(instance, meas_time, update_columns = False, write_clear_headers = True, segment_value = self._segment_value)
        fetched_rows = len(instance['data'])
        return fetched_rows
    
    
    def _fetch_data_from_source(self):
        #get last measurement time
        if self.validation_data['last_measurement_time']:
            # try to parse it from valid.json
            last_meas_time = self._date_unformatter.unformat(self.validation_data['last_measurement_time'])
            if not last_meas_time:
                raise Exception("Incorrect last_measurement_time date format.")
            """
            try:
                #try datetime
                last_meas_time = datetime.datetime.strptime(self.validation_data['last_measurement_time'], "%Y-%m-%d %H:%M:%S")
            except ValueError:
                try:
                    #try date
                    last_meas_time = datetime.datetime.strptime(self.validation_data['last_measurement_time'], "%Y-%m-%d")
                except ValueError:
                    raise Exception("Incorrect last_measurement_time date format.")
            """
        else:
            # get from db
            last_meas_time = self._get_last_meas_time()
        
        if self.validation_data['measurement_time']:
            # try to parse it from valid.json
            meas_time = self._date_unformatter.unformat(self.validation_data['measurement_time'])
            if not meas_time:
                raise Exception("Incorrect measurement_time date format.")
        else:
            meas_time = ''

        
        
        self._outer_conn = self._get_outer_connection()
       
        # get instance
        if not meas_time:        
            meas_time = last_meas_time
        if self._data['data_fetch_method'] == 'web service':
            meas_times = self._get_meas_times_web_service(last_meas_time)
            if meas_times['data']:
                meas_time = meas_times['data'][-1][0]

        instance = self._get_instance(meas_time, self._segment_value, last_meas_time)
        if self._data['data_fetch_method'] == 'web service':
            json_instance = self._outer_conn.get_json_result(meas_time)
        else:
            json_instance = self._outer_conn.get_json_result()
        
        # save data fetch
        self._jfile.save_data_fetch(
                                {'instance': json_instance, 
                                 'meas_time': meas_time.strftime('%Y-%m-%d %H:%M:%S'), 
                                 'generation_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
    
        # save sql query
        self._jfile.save_fetch_settings({'sql': self._data['data_fetch_command'],
                                        'segment_id': self._data['segment_id'],
                                        'source_database_connection_id': self._data['source_database_connection_id'],
                                        })        
        return instance, meas_time     

    def data_fetch(self, id1):
        """
        fetch data from outer source
        """
        instance, meas_time = self._fetch_data_from_source()

        # process instance and generate dataset json
        self._process_instance(instance, meas_time, update_columns = False, write_clear_headers = True, segment_value = self._segment_value)
        
        fetched_rows = len(instance['data'])
        """        
        # save clear fetched data
        self._jfile.save_data_fetch(
                                    {'instance': json_instance, 
                                     'meas_time': meas_time.strftime('%Y-%m-%d %H:%M:%S'), 
                                     'generation_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
        
        # save sql query
        self._jfile.save_fetch_settings({'sql': self._data['data_fetch_command'],
                                            'segment_id': self._data['segment_id'],
                                            'source_database_connection_id': self._data['source_database_connection_id'],
                                            })
        
        
        """
        return fetched_rows
    
    def metadata_update(self, id1):
        """
        update report metadata
        """
        # get instance
        instance, meas_time = self.get_saved_instance()
        
        if not instance:
            raise Exception("Cannot update metadata. Dataset is empty.")

        # force dataset class update titles
        self._data['last_report_column_metadata_update_time'] = None
        
        # process instance
        instance = self._process_instance(instance, meas_time, update_columns=True, write_clear_headers = True, segment_value = self._segment_value)
        
        # if exists validated data and sql then store them as last validated
        last_validation_fetch_settings = self._jfile.get_validation_fetch_settings()
        if last_validation_fetch_settings:
            last_validated_data = self._jfile.get_validated_dataset()
            if last_validated_data:
                self._jfile.save_last_validated_data_fetch(last_validated_data)
                self._jfile.save_last_validation_fetch_settings(last_validation_fetch_settings)
        
        return 0
    
    def pivot_generation(self, id1):
        """
        generate pivot and charts based on this pivot
        """
        # take all the pivots including disabled
        self._pivots = self._get_pivots(enabled_only = False)

        # check if there any pivots
        if not self._pivots:
            raise Exception("Report has no pivots")
        if not id1:
            raise Exception("Pivot id is not specified")
        
        #get enabled charts
        self._charts = self._get_charts()
        
        # find specified pivot
        pivots = filter(lambda pivot: pivot['report_data_set_pivot_id'] == id1, self._pivots)
        if not pivots:
            raise Exception("Incorrect pivot id")
        pivot = pivots[0]
        
        # get all chart based on current pivot
        pivot_charts = filter(lambda chart: chart['report_data_set_pivot_id'] == id1, self._charts)
        
        # get instance
        instance, meas_time = self.get_saved_instance()
        self._jfile.set_meas_time(meas_time)
        
        if not instance:
            raise Exception("Cannot create pivot. Dataset is empty.")

        # create dataset instance
        data_set_instance = self._process_instance(instance, meas_time, update_columns=False, write_clear_headers = True, segment_value = self._segment_value)

        # create pivot instance
        #data_set_pivot_instance = self._process_pivot(pivot, data_set_instance, self._segment_value)
        data_set_pivot_instance = self._process_pivot(pivot, data_set_instance)
        
        #prepare pivot data for charts
        pivot_formatted_header_rows = data_set_pivot_instance.get_formatted_header_rows()
        
        all_data = dict()
        all_data[pivot['report_data_set_pivot_id']] = pivot_formatted_header_rows
        
        chart_gen = ChartGenerator()

        for pivot_chart in pivot_charts:
            chart_gen.report_charts(self._id, self._segment_value_id, meas_time, 0, all_data, self._jfile, chart_id = pivot_chart['report_data_set_chart_id'])
        
        return len(pivot_formatted_header_rows['rows'])
    
    def chart_generation(self, id1):
        """
        generate chart 
        """
        return self._chart_process(id1, 'generate')

    def saving_chart(self, id1):
        """
        populate chart 'row values' 
        """
        return self._chart_process(id1, 'populate')

    def _chart_process(self, id1, command):
        """
        process chart 
        """
        # take all the pivots including disabled 
        self._pivots = self._get_pivots(enabled_only = False)
        
        # take all the charts including disabled 
        self._charts = self._get_charts(enabled_only = False)

        # check if there any charts
        if not self._charts:
            raise Exception("report has no chart")
        if not id1:
            raise Exception("chart id is not specified")
        
        
        # find specified chart
        charts = filter(lambda chart: chart['report_data_set_chart_id'] == id1, self._charts)

        if not charts:
            raise Exception("Incorrect chart id")
        chart = charts[0]

        all_data = dict()
        
        
        # get instance
        instance, meas_time = self.get_saved_instance()
        self._jfile.set_meas_time(meas_time)
         
        
        if not instance:
            raise Exception("Cannot create chart. Dataset is empty.")
        
        # create dataset instance
        data_set_instance = self._process_instance(instance, meas_time, update_columns = False, write_clear_headers = True, segment_value = self._segment_value)
        
        
        if chart['report_data_set_pivot_id']:
            # get pivot data
            index = chart['report_data_set_pivot_id']
            pivots = filter(lambda pivot: pivot['report_data_set_pivot_id'] == index, self._pivots)
            pivot = pivots[0]
            #data_set_pivot_instance = self._process_pivot(pivot, data_set_instance, self._segment_value)
            data_set_pivot_instance = self._process_pivot(pivot, data_set_instance)
            formatted_header_rows = data_set_pivot_instance.get_formatted_header_rows()
        else:
            # get dataset
            index = 0
            formatted_header_rows = data_set_instance.get_formatted_header_rows()

        if not formatted_header_rows:
            raise Exception("Cannot create chart. Dataset is empty.")

        #prepare data for charts
        all_data[index] = formatted_header_rows
        if command == 'generate':
            chart_gen = ChartGenerator()
            chart_gen.report_charts(self._id, self._segment_value_id, meas_time, 0, all_data, self._jfile, chart['report_data_set_chart_id'])
        elif command == 'populate':
            self._populate_row_values([chart], all_data)
        return 0

    def saving_report(self, id1):
        return 0
    
    def restore_data(self, id1):
        return 0
 def init(self, id):
     
     # init element
     super(ReportElementValidator, self).init(id)
     self._date_unformatter = DateUnformat()
     
     # do not save instances
     self._data['report_save_historical_instances_ind'] = 'N'
     # json file operation wrapper
     self._jfile = JFileValidator(self._path, self._id, self._data)
     self._instance_save_path = "%s%s/validation/" % (self._path, self._id)
     
     #get validation settings from valid.json generated by editor
     self.validation_data = self._jfile.get_validation_data()
     
     self._meas_interval = None
     
     if self.validation_data['measurement_interval_id']:
         res = self._db.Query("""SELECT interval_unit
                             FROM measurement_interval
                     WHERE 
                         measurement_interval_id =%s""",(self.validation_data['measurement_interval_id']))
         if res:
             self._meas_interval = self._db.record[0]['interval_unit']
             
     
     self.validation_data['data_fetch_command'] = self.validation_data['data_fetch_command'].strip().replace('\r\n','\n')
     if self.validation_data['source_database_connection_id']:
         self._data['source_database_connection_id'] = int(self.validation_data['source_database_connection_id'])
     else:
         self._data['source_database_connection_id'] = 0
         
     self._data['data_fetch_command'] = self.validation_data['data_fetch_command']
     self._data['data_fetch_method'] = self.validation_data['data_fetch_method']
     
     if self.validation_data['web_service_credentials_id']:
         self._data['web_service_credentials_id'] = int(self.validation_data['web_service_credentials_id'])
     else:
         self._data['web_service_credentials_id'] = 0
     
     if self.validation_data['measurement_interval_id']:
         self._data['measurement_interval_id'] = int(self.validation_data['measurement_interval_id'])
     else:
         self._data['measurement_interval_id'] = 0
         
     
     # set report segment -d
     if self.validation_data['segment_id'] and int(self.validation_data['segment_id']):
         self._data['segment_id'] = int(self.validation_data['segment_id'])
     else:
         self._data['segment_id'] = 0        
     
     # get segment data
     self._segment = self._get_segment()
     self._segment_values = self._get_segment_values()
     
     # get validation segment value id and set it as active
     if self.validation_data['segment_value_id'] and int(self.validation_data['segment_value_id']):
         segment_value_id = int(self.validation_data['segment_value_id'])
     else:
         segment_value_id = 0
     
     # get check current segment value to be in report segments
     if segment_value_id and self._segment and any(segment['segment_value_id'] == segment_value_id for segment in self._segment_values):
         self._segment_value = list(segment for segment in self._segment_values if segment['segment_value_id'] == segment_value_id)[0]
     elif self._segment_values and self._segment:
         raise Exception("segment_value_id does not match segment_id")
     else:
         self._segment_value = list()
     
     if self._segment_value:
         self._segment_value_id = self._segment_value['segment_value_id']
     else: 
         self._segment_value_id = 0
     
     self._jfile.set_segment_value(self._segment_value)
     self._jfile.set_segment(self._segment)