class View(Base):
    __tablename__ = 'views'
    id = Column(Integer, primary_key = True)
    title = Column(String(30), nullable=False, index = True, unique = True, info={'label':_(u'Title')})
    link_name = Column(String(30), nullable=False, unique=True, info={'label':_(u'Link name')})
    link_title = Column(String(30), info={'label':_(u'Link title (linking)')})
    description = Column(Text(200), info={'label':_(u'Description')})
    datasource = Column(enum_col, nullable=False, info={'disabled': True, 'choices': datasource_choices, 'label':_(u'Datasource')})
    buttontext = Column(String(15), info={'label':_(u'Button text')})
    reload_intervall = Column(SmallInteger, nullable=False, info={'label':_(u'Browser reload')}, default=30)
    layout_number_columns = Column(SmallInteger, nullable=False, info={'label': _(u'Number of columns')}, default=3)
    basic_layout = Column(Enum('table','single'), default='table', info={'label': _(u'Basic layout'), 'choices': [('table', _('Table')), ('single',_('Single dataset'))]})
    filters_id = Column(Integer, ForeignKey(ViewFilters.id))

    filters = relationship(
        ViewFilters,
        backref = 'view'
    )

    def update_view(self, view):
        del view._sa_instance_state 
        #self.__dict__.update(view.__dict__)
        for attribute, value in view.__dict__.iteritems():
            setattr(self, attribute, value)
        '''
        self.title = view.title
        self.link_name = view.link_name
        self.datasource = view.datasource
        self.buttontext = view.buttontext
        self.reload_intervall = view.reload_intervall
        self.layout_number_columns = view.layout_number_columns
        ''' def init_engine(db_uri):
def init_db():
def create_default_users():
def create_default_views():
def __add_column(name, view, link=""):
def __add_sort_by(name, view, order=""):
def __add_group_by(name, view):
def clear_db(): class ViewColumn(Base):
    __tablename__ = 'view_column'
    id = Column(Integer, primary_key=True)
    column = Column(enum_col, nullable=False, info={'choices':column_choices, 'label':_(u'Column')} )
    link = Column(String(30)) 
    parent_id = Column(Integer, ForeignKey(View.id), nullable=False)
    view = relationship(
        View,
        backref = 'view_column'
    ) def get_rows(datasource, columns_names, filters_string):
def query_data(datasource, columns, add_headers, filters_string, only_sites = [], limit = None):
def merge_data(data, columns):
    def worst_service_state(a, b):
    def worst_host_state(a, b): def compose(inner_func, *outer_funcs):
     """Compose multiple unary functions together into a single unary function"""
     if not outer_funcs:
         return inner_func
     outer_func = compose(*outer_funcs)
     return lambda *args, **kwargs: outer_func(inner_func(*args, **kwargs)) def multikeysort(items, columns, functions={}, getter=itemgetter):
    """Sort a list of dictionary objects or objects by multiple keys bidirectionally.

    Keyword Arguments:
    items -- A list of dictionary objects or objects
    columns -- A list of column names to sort by. Use -column to sort in descending order
    functions -- A Dictionary of Column Name -> Functions to normalize or process each column value
    getter -- Default "getter" if column function does not exist
              operator.itemgetter for Dictionaries
              operator.attrgetter for Objects
    """
    comparers = []
    for col in columns:
        column = col[1:] if col.startswith('-') else col
        if not column in functions:
            functions[column] = getter(column)
        comparers.append((functions[column], 1 if column == col else -1))

    def comparer(left, right):
        for func, polarity in comparers:
            result = cmp(func(left), func(right))
            if result:
                return polarity * result
        else:
            return 0
    return items.sort(cmp=comparer) class FiltersManager():
    """ A sort of proxy that facilitates filters usage. There is one FiltersManager per view display.
    """   
    def __init__(self):
        self.__filters = {}

    def set_filters(self, filters):
        self.__filters = filters

    def get_filter_query(self):
        filter_query = ''
        for name, filter_value in self.__filters.get_filters().iteritems():
            if filter_value:
                filter_query = filter_query + filters[name].filter(filter_value)             

        return filter_query
    
    def get_filters_name(self):
        return filters.keys() class ViewManager():
    """ A sort of proxy that facilitate views modification and views queries. """
    def __init__(self):
        self.__view = None
        self.__columns = None 
        self.__groupers = None
        self.__sorters = None
        self.__filters = None
    '''
    Set the view with the link_name. If a view is found, return the view found 
    '''
    def set_view(self, link_name):
        self.__view = View.query.filter_by(link_name=link_name).first()
        if self.__view:
            self.__columns = ViewColumn.query.filter_by(parent_id=self.__view.id).order_by(ViewColumn.id).all()
            self.__groupers = ViewGrouper.query.filter_by(parent_id=self.__view.id).order_by(ViewGrouper.id).all()
            self.__sorters = ViewSorter.query.filter_by(parent_id=self.__view.id).order_by(ViewSorter.id).all()
            self.__filters = self.__view.filters 
            return self.__view 
        else:
            return None
    
    def set_view_dummy(self, datasource):
        self.__view = View()
        self.__view.datasource = datasource

    def add_columns(self, columns, delete_before = False):
        if delete_before:
            for column in self.__columns:
                    db_session.delete(column)

        for column in columns:
            db_session.add(column)
        
        db_session.commit()

    def add_groupers(self, groupers, delete_before = False):
        if delete_before:
            for grouper in self.__groupers:
                    db_session.delete(grouper)

        for grouper in groupers:
            if grouper.column:
                db_session.add(grouper)
        
        db_session.commit()

    def add_sorters(self, sorters, delete_before = False):
        if delete_before:
            for sorter in self.__sorters:
                    db_session.delete(sorter)

        for sorter in sorters:
            if sorter.column:
                db_session.add(sorter)

        db_session.commit()

    def add_view(self, view):
        db_session.add(view)
        db_session.commit()
        
    def add_filters(self, filters):
        self.__view.filters = filters
        db_session.commit()

    def set_filters(self, filters):
        self.__filters.set_filters(filters)
    
    def set_extra_sorters(self, sorters):
        for colname, order in sorters.items():
            sorter = ViewSorter()
            sorter.column = colname
            sorter.sorter_option = order
            [self.__sorters.remove(sorter_item) for sorter_item in self.__sorters if sorter_item.column == colname]
            self.__sorters.append(sorter)

    def update_filters(self, filters):
        self.__view.filters.update(filters)
        db_session.commit()

    def get_filters(self):
        return self.__filters

    def get_hidden_filters(self):
        filters_tuples = []
        filters_obj = self.__filters
        for option, fil_col_names in cache_columns.iteritems():
            if getattr(filters_obj, option) == 'hide':
                filter_name = option.replace("_option","")
                column_name = filters[filter_name].column_names  
                filters_tuples.append((filter_name, column_name[0])) 
        return filters_tuples 


    def get_columns_choices(self):
        return get_columns_pairs(self.__view.datasource)

    def get_links_choices(self):
        views = View.query.all()
        links_choices = []
        links_choices.append(('',''))
        for x in views:
            if x.link_title:
                if not self.__view or not self.__view.link_title == x.link_title:
                    links_choices.append((x.link_name, x.link_title))
            else:
                if not self.__view or not self.__view.link_name == x.link_name:
                    links_choices.append((x.link_name, x.title))

        return links_choices 

    def get_columns(self):
        return self.__columns

    def get_sorters(self):
        return self.__sorters

    def get_sorters_columns(self):
        lst_columns = []
        for sorter in self.__sorters:
            lst_columns.append(sorter.column)
        return lst_columns

    def get_groupers(self):
        return self.__groupers
    
    def get_filter_display(self, form):
        lst_columns = cache_columns 
        lst_info = []
        for option, fil_col_names in lst_columns.iteritems():
            filter_name = option.replace("_option","")
            col_names = filters[filter_name].column_names
            filter_datasources = []
            for col_name in col_names:
                if painters.has_key(col_name):
                    filter_datasources = filter_datasources + painters[col_name].datasources
                if self.__view.datasource in filter_datasources:
                    option_field = getattr(form, option)
                    fields = []
                    for col in fil_col_names: 
                        fields.append(getattr(form, col))
                    lst_info.append(FilterFieldsInfo(option_field, fields))
        return lst_info
    
    def get_view(self):
        return self.__view

    def update_view(self, view):
        self.__view.update_view(view)
        db_session.commit() COL_HOST_NAME = 'host_name'
COL_HOST_STATE = 'host_state'
COL_SERVICE_STATE = 'service_state'
COL_LAST_CHECK = 'last_check'
COL_CHECK_COMMAND = 'check_command'
COL_SITE = 'site'
COL_SERVICE_DESCRIPTION = 'service_description'
COL_SERVICE_PLUGIN_OUTPUT = 'service_plugin_output'
COL_STATE_TYPE = 'state_type'
COL_OUTPUT = 'plugin_output'
COL_NUM_SERVICES_OK = 'num_services_ok'
COL_NUM_SERVICES_WARN = 'num_services_warn'
COL_NUM_SERVICES_CRIT = 'num_services_crit'
COL_NUM_SERVICES_UNKNOWN = 'num_services_unknown'
COL_NUM_SERVICES_PENDING = 'num_services_pending'
COL_HOST_IN_NOTIFICATION_PERIOD = 'host_in_notification_period'
COL_SERVICE_IN_NOTIFICATION_PERIOD = 'service_in_notification_period'
COL_HOST_ACKNOWLEDGED = 'host_acknowledged'
COL_HOST_SCHEDULED_DOWNTIME_DEPTH = 'host_scheduled_downtime_depth'
COL_SERVICE_SCHEDULED_DOWNTIME_DEPTH = 'service_scheduled_downtime_depth'
COL_HOST_CUSTOM_VARIABLE_NAMES = 'host_custom_variable_names'
COL_SERVICE_ACKNOWLEDGED = 'service_acknowledged'
def get_columns_pairs(datasources=None):
def get_columns_name(datasources=None):
def get_datasources_available():
from app.db_model.view import View
from app.db_model.base import db_session
from app.db_model.viewColumn import ViewColumn
from app.lib import livestatus_query
from app.lib.datasources import multisite_datasources as datasources
from app.lib.multi_keys_sorting import compose, multikeysort
from app.managers.filters_manager import FiltersManager
from app.managers.view_manager import ViewManager
from app.model.columns.builtin import painters
from operator import itemgetter, methodcaller
import copy
#   This file is part of Sageo
#   
#   Sageo is free software: you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation, either version 3 of the License, or
#   (at your option) any later version.
#
#   Sageo is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU General Public License
#   along with Sageo.  If not, see <http://www.gnu.org/licenses/>



class DataRowsManager():
    """ A sort of proxy that facilitate gathering data from LiveStatus without knowing implementation details. """
    def __init__(self):
        self.__view_manager = None
        self.__filters_manager = None
    '''
    Set the view with the link_name. If a view is found, return true, else return false.
    '''
    def set_view(self, link_name):
        self.__view_manager = ViewManager()
        if self.__view_manager.set_view(link_name):
            self.__filters_manager = FiltersManager()
            self.update_filters()
            return True
        else:
            return False

    def update_filters(self):
        self.__filters_manager.set_filters(self.__view_manager.get_filters())

    def get_group_columns_list(self):
        groupers = self.__view_manager.get_groupers()
        group_list = []
        if groupers:
            for group in groupers:
                group_list.append(group.column)
        return group_list

    def get_link_data(self):
        link_data = {}
        columns = self.__view_manager.get_columns()
        for col in columns:
            if col.link:
                linked_view_manager = ViewManager()
                linked_view_manager.set_view(col.link)
                link_details = {}
                hidden_filters = linked_view_manager.get_hidden_filters()
                link_details['link_name'] = col.link
                link_details['filters'] = hidden_filters 
                link_data[col.column] = link_details 

        return link_data
        

    def get_rows(self):
        """ get rows corresponding to the query builded with the view and its options """
        # prepare basic parameter datasource and columns_name
        datasource = datasources[self.__view_manager.get_view().datasource]        
        columns_name = self.get_asked_columns_name()
        filters_string = self.__filters_manager.get_filter_query() 
        print '\nfilters: ' + filters_string
        columns_name += self.__view_manager.get_sorters_columns()
        rows = livestatus_query.get_rows(datasource, columns_name, filters_string)         

        if not rows == []:
            groupers = self.__view_manager.get_groupers()
            sort_list = []
            for grouper in groupers:
                sort_list.append((grouper.column,0))
            rows = self.group(rows, self.get_group_columns_list())  
            rows = sorted(list((k, v) for k,v in rows.items()))

            sorters = self.__view_manager.get_sorters()
            if sorters:
                sort_list = []
                for sorter in sorters:
                    sort_list.append((sorter.column,sorter.sorter_option))                
                rows = self.__sorted_rows(rows, sort_list)

            rows = self.__readable_rows(rows)
        return rows

    def get_sorters_dic(self):
        sorters = {}
        for sorter in self.__view_manager.get_sorters():
            sorters[sorter.column] = sorter.sorter_option 

        return sorters

    def __readable_rows(self, rows):
        rows_readable = rows 
        for group in rows_readable:
            for row in group[1]:
                for name, value in row.iteritems():
                    if name in painters.keys():
                        row[name] = painters[name].get_readable(row)
        return rows_readable
                
    def __sorted_rows(self, rows, sort_list):
        arguments = []
        callers = {}
        for sorter in sort_list:
            prefix = ''
            sort_order = sorter[1]
            column = sorter[0]
            if sort_order == '1':
                prefix = '-'
            arguments.append(prefix + column)
            if isinstance(rows[0][1][0][column], basestring): 
                get_lower = compose(itemgetter(column), methodcaller('lower'))
                callers[column] = get_lower

        for group in rows:

            multikeysort(group[1], arguments, callers)