/*
 * kakumei_posts.c
 *
 * Posts management
 *
 * Author: Dario Rodriguez dario@softhome.net
 * This program is licensed under the terms of the Affero GPL v1+
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include "loglib.h"
#include "kakumei.h"
#include "kakumei_posts.h"

#define MAXPOSTS 2000000

int
post_new(kakumei *ka, char *user, char *title, char *text)
{
        int last;
        int num;
        char filename[1024];
        char dirname[1024];
        FILE *f;
        struct stat st;
        if(ka==NULL || user==NULL || user[0]=='\0' || text==NULL || text[0]=='\0') {
                log_write("POST","sanity check error\n");
                return(-1);
        }
        last=post_last(ka);
        if(last==-1)
                last=0; /* post number starts on 1 (last+1)*/
        filename[0]='\0';
        for(num=last+1;num<MAXPOSTS;num++) {
                snprintf(filename,sizeof(filename),"%s/%04i/%04i.json",POSTSDIR,num/10000,num%10000);
                filename[sizeof(filename)-1]='\0';
                if(stat(filename,&st)!=0)
                        break; /* this one is ok: file doesn't exist */
        }
        if(filename[0]=='\0' || num>=MAXPOSTS) {
                log_write("POST","couldn't generate filename or too many posts\n");
                return(-1);
        }
        /* create dir structure */
        mkdir(DATADIR,0700);
        mkdir(POSTSDIR,0700);
        snprintf(dirname,sizeof(dirname),"%s/%04i",POSTSDIR,num/10000);
        dirname[sizeof(dirname)-1]='\0';
        mkdir(dirname,0700);
        /* save the new post */
        if((f=fopen(filename,"w"))==NULL) {
                log_write("POST","couldn't save post\n");
                return(-1);
        }
        fprintf(f,"{\n  \"author\":\"%s\",\n",user);
        fprintf(f,"  \"date\":%li,\n",(long)time(NULL));
        fprintf(f,"  \"title\":\"%s\",\n",title);
        fprintf(f,"  \"text\":\"%s\",\n",text);
        fprintf(f,"  \"comments\":[\n]}\n");
        fclose(f),f=NULL;
        /* save the "last" mark */
        snprintf(filename,sizeof(filename)-1,"%s/%s",POSTSDIR,"last");
        filename[sizeof(filename)-1]='\0';
        if((f=fopen(filename,"w"))!=NULL) {
                fprintf(f,"%i",num);
                fclose(f),f=NULL;
        }
        return(0);
}

int
post_last(kakumei *ka)
{
        char readbuf[128];
        char filename[1024];
        int fd;
        snprintf(filename,sizeof(filename)-1,"%s/%s",POSTSDIR,"last");
        filename[sizeof(filename)-1]='\0';
        if((fd=open(filename,O_RDONLY))==-1) {
                log_write("POST","couldn't get last post number\n");
                return(-1);
        }
        memset(readbuf,0,sizeof(readbuf));
        read(fd,readbuf,sizeof(readbuf)-1);
        close(fd),fd=-1;
        return(atoi(readbuf));
}

int
post_get(kakumei *ka, int num, char *filename, int filenamesize)
{
        struct stat st;
        if(ka==NULL || num<0 || filename==NULL || filenamesize<=0) {
                log_write("POST","Sanity check error\n");
                return(-1);
        }
        snprintf(filename,filenamesize,"%s/%04i/%04i.json",POSTSDIR,num/10000,num%10000);
        filename[filenamesize-1]='\0';
        if(stat(filename,&st)!=0) {
                log_write("POST","Post file doesn't exist\n");
                return(-1); /* file doesn't exist */
        }
        return(0);
}

int
post_addcomment(kakumei *ka, int postnum, char *user, char *text)
{
        char filename[1024];
        char buf[16];
        FILE *f;
        int off;
        if(ka==NULL || postnum<0 || user==NULL || text==NULL) {
                log_write("POST","Sanity check error\n");
                return(-1);
        }
        if(post_get(ka,postnum,filename,sizeof(filename))!=0)
                return(-1);
        if((f=fopen(filename,"r+"))==NULL) {
                log_write("POST","Couldn't open post file for appending\n");
                return(-1);
        }
        fseek(f,-5,SEEK_END);
        if(fread(buf,1,5,f)!=5) {
                fclose(f),f=NULL;
                log_write("POST","Post file contents are too small\n");
                return(-1);
        }
        off=(buf[4]=='\n')?1:0;
        if(buf[4-off]!='}' || buf[3-off]!=']' || buf[2-off]!='\n') {
                fclose(f),f=NULL;
                log_write("POST","Post file contents are corrupted\n");
                return(-1);
        }
        fseek(f,-4-off,SEEK_END);
        fprintf(f,"%c%s\n    { \"author\":\"%s\",\"date\":%li,\"text\":\"%s\"}\n]}",
          buf[1-off],(buf[1-off]!='[')?",":"",
          user,(long)time(NULL),text);
        fclose(f),f=NULL;
        return(0);
}