/* appjet:version 0.1 */
/*<script>
This work is licensed under a Creative Commons Attribution-Noncommercial 3.0 United States License
http://creativecommons.org/licenses/by-nc/3.0/us/

...Vortices v2.0
yet another social news network...
*/

import('lib-clean-urls','storage','lib-general','lib-account','lib-jquery','lib-markdown','lib-json','lib-atom','lib-tags')
var url = request.path

// /*
if(appjet.appName != 'v-test.js' && appjet.appName != 'v-test' && !appjet.isPreview && request.headers.Host != 'vortices.vezquex.com')
{
        response.redirect('http://vortices.vezquex.com' + url + paramGen(null, true))
}
// */

// storage.laOps.use.css = false
        
if(!storage.laOps.newUser) storage.laOps.newUser = {
        values: {
                upvotes: 0,
                downvotes: 0,
                postCount: 0,
                liked: 0
        },
        collections: 'votes,contacts'
}
//storage.laOps = 0

collectionsAre(['nodes','files'])
var initialComments = 2
var mp3id = 0
var currentTime = new Date()
var algorithm = (rp.sort || request.cookies.sort || 'Hot')

var out = {
        container: DIV({'class':'container'}),
        logo: A({href: '/', id: 'logo'}, IMG({alt:'Vortices', src: 'http://files.appjet.net/download?id=obj-O1ayfS0jr'})),
        footer: P('©2009'),
        analytics: ''
}

var container = out.container

/*        Feeds
-----------------------------------------------------*/

function get_feed(filt)
{
        var base
        if(filt)
                rp = filt
        else
                delete rp.feed

        if(rp)
        {
                base = storage.nodes.filter(rp)
        }
        else base = storage.nodes.filter({parent: 'top', deleted: undefined}) //main feed

        base = base.sort(sorting['New']).limit(20)

        var entries = {
                base: base,
                i: 0,
                forEach: function(f) {
                        this.base.forEach(function(n) {
                                return f({
                                        author: n.author,
                                        title: n.title,
                                        link: n.link||'http://vortices.vezquex.com/node/'+n.id,
                                        id: 'tag:vortices.vezquex.com,2008:obj/'+n.id,
                                        updated: n.time,
                                        summary: '',
                                        content: markdown(n.text)
                        })})}
                }
        page.setMode('plain')
        response.setHeader('Content-Type', 'application/atom+xml')
        print(raw(getMainFeed(
                                'Vortices',
                                'http://vortices.vezquex.com/feed',
                                'tag:vortices.vezquex.com,2008:/1',
                                base.first().time,
                                entries
        )))
        response.stop(true)
}

/*        Voting
-----------------------------------------------------*/

function post_ajaxvote()
{
        page.setMode('plain')
        if(!user) r = {status: 'Sign in or register before voting.'}
        else
        {
                var r = {status: false, score: vote()}
        }
        print(raw(JSON.stringify(r)))
        response.stop()
}

function vote()
{
        var thisvote
        thisvote = user.votes.filter({node: rp.on}).first()
        var node = getStorable(rp.on)
        if(!thisvote)
        {
                user.votes.add({node: rp.on, type: rp.vote})
                node[rp.vote + 'votes'] += 1
        }
        else if(thisvote.type != rp.vote)
        {
                if(rp.vote == 'down')
                {
                        thisvote.type = 'down'
                        node.downvotes += 1
                        node.upvotes -= 1
                }
                else
                {
                        thisvote.type = 'up'
                        node.upvotes += 1
                        node.downvotes -= 1
                }
        }
        else //undo vote
        {
                node[rp.vote+'votes'] -= 1
                user.votes.remove({node: rp.on})
        }
        return score(node)
}

function printPage()
{
        page.setTitle('Vortices :: type for justice')
        page.setFavicon('http://files.appjet.net/download?id=obj-OWYK1dKFh')

        var sorts = ['Hot', 'New', 'Top', 'Replies'] //'A-Z'
        var resort = UL()
        sorts.forEach(function(s){
                resort.push(LI({id: s}, A({href: paramGen({'sort': s}, true), onclick: "setCookie('sort','"+s+"')", rel: 'nofollow'}, s)))
        })

        var tags = UL()
        storage.tags.sortBy('-count').limit(5).forEach(function(tag){
                tags.push(LI(A({href: '/tag/'+tag.name}, tag.name)))//tag.count //tag.name.substring(0, 1).toUpperCase() + tag.name.substring(1, tag.name.length)
        })
        
        out.menu = UL({'class': 'sidebar'},//id: 'menu', 
                LI({id: 'sort'},
                        'Sort'
                        ,resort
                ),
                LI({id: 'tags'},
                        link('/tags','Tags'),
                        tags
                )
        )

        if(user)
        {
                if(!rp.edit) out.form = postForm()
                out.menu.unshift(
                        LI(userLink(user),
                                UL(
                                        LI(link('/posts/'+user.alias,'Posts')),
                                        LI(link('/profile/'+user.alias,'Profile')),
                                        LI(link('/subscriptions/'+user.id, 'Subscriptions')),
                                        LI(link('/liked/'+user.alias, 'Liked')),
                                        LI(la.signOut())
                                )
                        )
                )
        }
        else
        {
                out.form = la.signIn(null, true)
//                container.push(statusBanner("Welcome to Vortices, the all-purpose social network for friends, news, and life."))
        }

        print(
                DIV({id:'page'},
                        DIV(
                                out.logo,
                                out.form
                        ),
                        out.menu,
                        out.container,
                        DIV({id: 'footer'}, out.footer)
//                          ,DIV({id: 'up'}, A({href: '#', title: 'Jump to Top'}, '^'))
                )
        )
}

//Editing
function get_edit()
{
        var node = getStorable(rp.edit)
        if(request.method == 'GET' && (node.wiki_tag == 'wiki' || node.author == user.alias) && !node.deleted)
        {
                var tags = html(
                        accessTags(node).sort().map(function(tag){
                                        return SPAN(tag, SUP(A({rel: 'nofollow', href: '/untag'+paramGen({id: node.id, tag: tag, redirect: '/edit/'+node.id})}, 'x')))
                        })
                        .join(' ')
                )
                print(
                        H2('Edit'),
                        FORM({action:'/edit', 'class': 'submit', method:'post'},
                                INPUT({type:'hidden',name:'node',value:node.id}),
                                                LABEL(SPAN('Title'), INPUT({name:'title', autocomplete:'off', type: 'text', value:node.title||'', maxlength:255})),
                                                INPUT({type:'submit', value: 'Save'}),
                                        LABEL(SPAN('URL'), INPUT({name:'link', autocomplete:'off', type: 'text', value:node.link||''})),
                                LABEL(SPAN('Text'), TEXTAREA({name:'text'}, raw(node.text))),
                                        LABEL(SPAN('Tags'), INPUT({name:'tags', type: 'text', maxlength:255})),
                                        P(tags)
                        )
                )
        }
        else
        {
                status('Error: You cannot edit this post. Make sure that you are logged in and that you authored this or it is a wiki.')
        }
}

function get_vote()
{
        if(rp.vote && rp.on)
        {
                var thisvote
                thisvote = user.votes.filter({node: rp.on}).first()
                var node = getStorable(rp.on)
                if(!thisvote)
                {
                        user.votes.add({node: rp.on, type: rp.vote})
                        node[rp.vote + 'votes'] += 1
                }
                else if(thisvote.type != rp.vote)
                {
                        if(rp.vote == 'down')
                        {
                                thisvote.type = 'down'
                                node.downvotes += 1
                                node.upvotes -= 1
                        }
                        else
                        {
                                thisvote.type = 'up'
                                node.upvotes += 1
                                node.downvotes -= 1
                        }
                }
                else //undo vote
                {
                        node[rp.vote+'votes'] -= 1
                        user.votes.remove({node: rp.on})
                }
        }
}

/*        Main Posting/Reply Form
-----------------------------------------------------*/
function postForm(ops)
{
        ops = extend({button: 'Post'}, ops)
        var id = (ops.parent||'main')+'-form'
   
        var form = FORM({method:'post', action:'/submit', id:id, 'class':'submit', enctype:'multipart/form-data'},
                INPUT({name:'title', type: 'text'}),//, value: 'what\'s on your mind?'
                INPUT({type:'submit', value: ops.button}),
                P({'class':'ops'},
                        A({'class':'toggler', href:'#'},'Link'),
                        A({'class':'toggler', href:'#'},'Text'),
//                         A({'class':'toggler', href:'#'},'Upload'),
                        A({'class':'toggler', href:'#'},'Tags')
                ),
                LABEL({'class':'toggle t-Link'}, SPAN('URL'), INPUT({value: 'http://', name:'link', type: 'text'})),
                LABEL({'class':'toggle t-Text'}, SPAN('Text'), TEXTAREA({name:'text'})),
//                 LABEL({'class':'toggle t-Upload'}, SPAN('Upload'), INPUT({type:'file', name:'upload'})),
                LABEL({'class':'toggle t-Tags'}, SPAN('Tags'), INPUT({value: '', name:'tags', type: 'text', maxlength:255}))
        )
                
        return form
}

function get_reply(parent, fields)
{
        at = rp.at
        if(!fields) fields = {action: 'submit', title: '',link: '',text: ''}
        if(!parent) var parent = rp.reply
        if(at == 'undefined') at = rp.reply
        var header = 'Reply'
        if(parent) get_node(parent,true)
        else header = 'Post'
        print(H2({id:'reply'},header))
        var form = FORM({action:'/'+fields.action, 'class': 'submit', method:'post', enctype:'multipart/form-data'})
        if(fields.title != undefined)
                form.push(LABEL(SPAN('Title'),INPUT({value: fields.title||'', id: 'title', name:'title',maxlength:255, type: 'text'})), BR())
        if(fields.link != undefined)
                form.push(LABEL(SPAN('URL'),INPUT({value: fields.link||'http://', name:'link', type: 'text'})), BR())
        form.push(LABEL(SPAN('Text'),TEXTAREA({name:'text'},fields.text||'')), BR())
        if(fields.tags != undefined)
                form.push(LABEL(SPAN('Tags'),INPUT({value: fields.tags||'', name:'tags', type: 'text'})), BR())
        form.push(
                INPUT({type:'submit',value:'Post'}),
                INPUT({type:'hidden',name:'parent',value:parent}),
                INPUT({type:'hidden',name:'at',value:at})
        )
        print(form)

}

function get_post()
{
        page.setTitle('Post - Vortices')
        if(user) get_reply(undefined, {action: 'submit', title: '',link: '',text: '',tags: ''})
}

function post_submit(ajax)
{
        var node = {
                author: user.alias,
                downvotes: 0,
                replies: 0,
                time: currentTime,
                upvotes: 1,
                parent: rp.parent || 'top'
        }

        if(rp.link && rp.link != 'http://')
        {
                node.link = trim(rp.link)
        }
        else
        {
                if(rp.text == '')// && rp.parent
                {
                        rp.text = rp.title
                        delete rp.title
                }
        }

        if(rp.title) node.title = trim(rp.title)
        node.text = sanitize(rp.text||'')

        node = storage.nodes.add(node)
        
/*
        try
        {
                var file = appjet._native.request_uploadedFile('upload')
                file = storage.files.add({
                        file: file,
                        author: user.alias,
                        filename: file.filesystemName,
                })
                node.file = file
                addTags(node, 'file')
        }
        catch(e){}
*/
        
        user.votes.add({node: node.id, type: 'up'})
        user.postCount += 1
        if(rp.tags) addTags(node, rp.tags)
        if(node.parent)
        {
//                 node.ancestor = parent.ancestor
                var parent = node.parent
                while(parent != 'top')
                {
                        parent = getStorable(parent)
                        parent.replies += 1
                        parent = parent.parent
                }
        }
        
        if(ajax)
        {
                return html(renderNode(node, 0, false))
        }
        else
        {
                if(!rp.at) rp.at = node.id
                response.redirect('node/'+rp.at+'#'+node.id)
//                 print(request.headers, request.params)
        }
}

function post_ajaxsubmit()
{
        if(!user) r = {error: 'Sign in or register before voting.'}
        else
        {
                var r = {error: false, html: post_submit(true)._text}
        }
        page.setMode('plain')
        print(raw(JSON.stringify(r)))
        response.stop()
}

function post_edit()
{
        var node = getStorable(rp.node)
        var fields = ['title','link']
        fields.forEach(function(param)
        {
                node[param] = rp[param] ? trim(rp[param]) : ''
        })
        if(rp.tags)
        {
                addTags(node, rp.tags)
        }
        node.text = sanitize(rp.text)
        node.edit = currentTime
        var where = rp.at
        if(!where) where = node.id
        rp = []
        response.redirect('node/'+where)
}

var general =
{

        'A-Z': function(a, b, prop)
        {
                (a[prop]||'').toLowerCase().localeCompare((b[prop]||'').toLowerCase())
        },

        'greatest': function(a, b, prop) { return b[prop] - a[prop] },
        'longest': function(a, b, prop) { return b[prop].size() - a[prop].size() }
}

var sorting = {

        user: {

                'A-Z': function(a, b) { return general['A-Z'](a, b, 'login')},

                Replies: function(a, b) { return general['greatest'](a, b, 'postCount')},

                Hot: function(a, b) { return (b.upvotes - b.downvotes) * Math.abs(b.upvotes - b.downvotes) / (currentTime - b.registered.getTime()) - (a.upvotes - a.downvotes) * Math.abs(a.upvotes - a.downvotes) / (currentTime - a.registered.getTime()) }
        },

        'A-Z': function(a, b) { return general['A-Z'](a, b, 'title')},

        Top: function(a, b) { return b.upvotes - b.downvotes - a.upvotes + a.downvotes },

        Hot: function(a, b) { return (b.upvotes - b.downvotes) * Math.abs(b.upvotes - b.downvotes) / (currentTime - b.time.getTime()) - (a.upvotes - a.downvotes) * Math.abs(a.upvotes - a.downvotes) / (currentTime - a.time.getTime()) },

        RedditHot: function(a, b) { return RedditHot(b) - RedditHot(a) },

        New: function(a, b) { return a.id > b.id },
        Old: function(a, b) { return a.id < b.id },

        Replies: