from parsable import parsable
import pomagma.analyst
import pomagma.analyst.compiler
import sys

theories = {
    'unit': '''
        CLOSED t         -----------------   LESS APP f TOP APP g TOP
        FIXES V t        EQUAL APP t x TOP   LESS APP f I APP g I
        FIXES t I        EQUAL APP t x I     ------------------------
        LESS APP J I t                       LESS COMP f t COMP g t
        ''',
    'semi': '''
        CLOSED t      -----------------   LESS APP f TOP APP g TOP
        FIXES V t     EQUAL APP t x TOP   LESS APP f I APP g I
        FIXES t BOT   EQUAL APP t x I     LESS APP f BOT APP g BOT
        FIXES t I     EQUAL APP t x BOT   ------------------------
                                          LESS COMP f t COMP g t
        ''',
    'bool': '''
        CLOSED t      -----------------   LESS APP f TOP APP g TOP
        FIXES V t     EQUAL APP t x TOP   LESS APP f K APP g K
        FIXES t BOT   EQUAL APP t x K     LESS APP f F APP g F
        FIXES t K     EQUAL APP t x F     LESS APP f BOT APP g BOT
        FIXES t F     EQUAL APP t x BOT   ------------------------
                                          LESS COMP f t COMP g t
        ''',
    'boool': '''
        CLOSED t      -----------------   LESS APP f TOP APP g TOP
        FIXES V t     EQUAL APP t x TOP   LESS APP f J APP g J
        FIXES t BOT   EQUAL APP t x J     LESS APP f K APP g K
        FIXES t K     EQUAL APP t x K     LESS APP f F APP g F
        FIXES t F     EQUAL APP t x F     LESS APP f BOT APP g BOT
        FIXES t J     EQUAL APP t x BOT   ------------------------
                                          LESS COMP f t COMP g t
        ''',
    'unit_test': '''
                         -----------------   LESS APP f TOP APP g TOP
        FIXES V t        EQUAL APP t x TOP   LESS APP f I APP g I
        FIXES t I        EQUAL APP t x I     ------------------------
        LESS APP J I t                       LESS COMP f t COMP g t
        ''',
    'semi_test': '''
                      -----------------   LESS APP f TOP APP g TOP
        FIXES V t     EQUAL APP t x TOP   LESS APP f I APP g I
        FIXES t BOT   EQUAL APP t x I     LESS APP f BOT APP g BOT
        FIXES t I     EQUAL APP t x BOT   ------------------------
                                          LESS COMP f t COMP g t
        ''',
}


def print_solutions(solutions):
    print 'Necessary:'
    for term in solutions['necessary']:
        print '  {}'.format(term)
    print 'Possible:'
    for term in solutions['possible']:
        print '  {}'.format(term)


@parsable
def show_define(name=None):
    '''
    Print program generated by analyst.compiler.compile_solver used in define.
    Available types: unit, semi, bool, boool
    '''
    if name not in theories:
        print 'Try one of: {}'.format(' '.join(sorted(theories)))
        sys.exit(1)
    print pomagma.analyst.compiler.compile_solver('t', theories[name])


@parsable
def define(name=None, max_solutions=32, address=pomagma.analyst.ADDRESS):
    '''
    Conjecture definitions of a type.
    Available types: unit, semi, bool, boool
    '''
    if name not in theories:
        print 'Try one of: {}'.format(' '.join(sorted(theories)))
        sys.exit(1)
    with pomagma.analyst.connect(address) as db:
        solutions = db.solve('t', theories[name], max_solutions)
    print_solutions(solutions)
    return solutions


@parsable
def sr_pairs(max_solutions=32, address=pomagma.analyst.ADDRESS):
    '''
    Find section,retract pairs (i.e. pairs below A).
    '''
    expr = 'FUN f APP APP f s r'    # coding of the pair (s, r)
    theory = '''
        CLOSED s   NLESS s BOT      # s is closed and nontrivial
        CLOSED r   NLESS r BOT      # r is closed and nontrivial
        LESS COMP r s I             # (s, r) is a section-retract pair
        '''
    with pomagma.analyst.connect(address) as db:
        solutions = db.solve(expr, theory, max_solutions)
        pairs = (
            [(sr, True) for sr in solutions['necessary']] +
            [(sr, False) for sr in solutions['possible']])
        sections = db.simplify(['APP {} K'.format(sr) for sr, _ in pairs])
        retracts = db.simplify(['APP {} F'.format(sr) for sr, _ in pairs])
    parts = zip(pairs, sections, retracts)
    solutions = {
        'necessary': [(sr, s, r) for (sr, n), s, r in parts if n],
        'possible': [(sr, s, r) for (sr, n), s, r in parts if not n],
    }
    print_solutions(solutions)
    return solutions


if __name__ == '__main__':
    parsable()
