# table.py -- tag and filter implementation
from django import template
from django.shortcuts import render_to_response
from django.template.loader import get_template

def reshape( lst, ncols, nrows, horiz=True ):
    """Change shape of list lst (like APL, J, K, NumPy).
    Return list of lists: ncols x nrows. horiz - is the
    table direction (horizontal or vertical if horiz is
    False). Empty cells will be with ''
    """
    if not ncols and not nrows: return lst

    w = ncols or len(lst)/nrows + (1 if len(lst)%nrows else 0)
    h = nrows or len(lst)/ncols + (1 if len(lst)%ncols else 0)
    
    if horiz:
        flatten = lambda irow, icol: icol + irow*w
    else:
        flatten = lambda irow, icol: irow + icol*h

    rows = []
    for irow in range( h ):
        col = []
        for icol in range( w ):
            iflat = flatten( irow, icol )
            el = '' if iflat >= len(lst) else lst[iflat]
            col.append( el )
        rows.append( col )

    return rows


register = template.Library()

@register.tag
def table( parser, token ):
    """ Push in context 'table_obj' object - list of lists, result
    of reshape function (see it)"""
    try:
        # lst - name of the list in the context, shape is string like 'H:4x?'|'V:2x2'|'?x3'
        # 'H' - horiz direction, 'V' - vertical direction, '?' - computable size, digit -
        # fixed size (see reshape function!)
        tag, lst, shape = token.split_contents()
    except ValueError:
        sx = 'tag %r requires two arguments'%token.contents[0]
        raise template.TemplateSyntaxError( sx )
    shape = shape[1:-1].upper() # cut .. from ".."
    if shape.startswith( 'V:' ):
        horiz = False
        shape = shape[2:]
    elif shape.startswith( 'H:' ):
        horiz = True
        shape = shape[2:]
    else:
        horiz = True
    w,h = shape.split( 'X' )
    w = None if w == '?' else int(w)
    h = None if h == '?' else int(h)
    if not h and not w:
        raise template.TemplateSyntaxError( 'only one axis may be unknown (?)' )

    nodes = parser.parse( ('endtable',) )
    parser.delete_first_token()
    return TableNode( nodes, lst, w, h, horiz )

class TableNode( template.Node ):
    def __init__( self, nodes, lst, w, h, horiz ):
        self.nodes = nodes
        self.lst = lst
        self.w = w
        self.h = h
        self.horiz = horiz
    def render( self, context ):
        # get list from context by it's name
        res = reshape( context[self.lst], self.w, self.h, self.horiz )
        context.push()
        context[ 'table_obj' ] = res
        txt = self.nodes.render( context )
        context.pop()
        return txt

@register.filter
def flatindex( forloop ):
    """Existed in the nested loops return flat index
    (index of flat list). For example:
    like in C N-th dimension array may look like
    flat array with ONE, flat index. This tag generate
    this flat index for nested loops in django template (see nested {% for...%})"""
    loop = forloop
    level = 0
    ret = 0
    nestedlen = 1
    while True:
        if level == 0:
            ret += loop['counter0']
            # length of current level * size of previous levels is
            # "weight" of ranking level. Ranking level add
            # nestedlen to flatindex if move by 1 (like hypercube).
            nestedlen *= loop['counter0'] + loop['revcounter0'] + 1 
        else:
            ret += loop['counter0']*nestedlen

        # go to next-up level
        parentloop = loop.get('parentloop', None)
        if parentloop:
            loop = parentloop
        else:
            break
        level += 1
    return ret
