#include <u.h>
#include <libc.h>
#include <draw.h>
#include <event.h>
#include <panel.h>
#include "mothra.h"

static int
hexdigit(int c)
{
       if(c >= '0' && c <= '9')
               return c-'0';
       if(c >= 'a' && c <= 'f')
               return c-'a'+10;
       if(c >= 'A' && c <= 'F')
               return c-'A'+10;
       return -1;
}

static int
dechex(uchar *out, int lim, char *in, int n)
{
       uchar *start, *end;
       int c;

       start = out;
       end = start + lim;
       while(n-- > 0 && out < end){
               c = *in++;
               if(c == 0)
                       break;
               if(c & 0x80)
                       return -1;
               if(c == '%'){
                       n -= 2;
                       if(n < 0 || (c = hexdigit(*in++)) == -1)
                               return -1;
                       if((c = (c << 4) | hexdigit(*in++)) == -1)
                               return -1;
               }
               *out++ = c;
       }
       return out - start;
}

static int
dataget(Url *url)
{
       int (*decfun)(uchar *, int, char *, int) = dechex;
       char *s, *p;
       int fd, n, m;

       s = url->reltext;
       if(cistrncmp(s, "data:", 5) != 0)
               return -1;
       s += 5;
       if((p = strchr(s, ',')) != nil){
               *p = 0;
               if(strstr(s, "base64") != nil)
                       decfun = dec64;
               *p = ',';
               s = p+1;
       } else
               s = strchr(s, 0);
       n = strlen(s);
       m = n+64;
       p = malloc(m);
       strcpy(p, "/tmp/duXXXXXXXXXXX");
       if((fd = create(mktemp(p), ORDWR|ORCLOSE, 0600)) < 0){
               free(p);
               return -1;
       }
       if((m = (*decfun)((uchar*)p, m, s, n)) < 0 || write(fd, p, m) != m){
               free(p);
               close(fd);
               return -1;
       }
       free(p);
       seek(fd, 0, 0);
       return fd;
}

static int
fileget(Url *url)
{
       char *rel, *base, *x;

       rel = base = nil;
       if(cistrncmp(url->basename, "file:", 5) == 0)
               base = url->basename+5;
       if(cistrncmp(url->reltext, "file:", 5) == 0)
               rel = url->reltext+5;
       if(rel == nil && base == nil)
               return -1;
       if(rel == nil)
               rel = url->reltext;
       if(base && base[0] == '/' && rel[0] != '/'){
               if(x = strrchr(base, '/'))
                       *x = 0;
               snprint(url->fullname, sizeof(url->fullname), "%s/%s", base, rel);
               if(x)   *x = '/';
       }else
               snprint(url->fullname, sizeof(url->fullname), "%s", rel);
       url->tag[0] = 0;
       if(x = strrchr(url->fullname, '#')){
               *x++ = 0;
               nstrcpy(url->tag, x, sizeof(url->tag));
       }
       base = cleanname(url->fullname);
       x = base + strlen(base)+1;
       if((x - base) > sizeof(url->fullname)-5)
               return -1;
       memmove(url->fullname+5, base, x - base);
       memmove(url->fullname, "file:", 5);
       return open(url->fullname+5, OREAD);
}

char *mtpt="/mnt/web";

static int
webclone(Url *url, char *buf, int nbuf)
{
       int n, conn, fd;

       snprint(buf, nbuf, "%s/clone", mtpt);
       if((fd = open(buf, ORDWR)) < 0)
               return -1;
       if((n = read(fd, buf, nbuf-1)) <= 0){
               close(fd);
               return -1;
       }
       buf[n] = 0;
       conn = atoi(buf);
       if(url && url->reltext[0]){
               if(url->basename[0]){
                       n = snprint(buf, nbuf, "baseurl %s", url->basename);
                       write(fd, buf, n);
               }
               n = snprint(buf, nbuf, "url %s", url->reltext);
               if(write(fd, buf, n) < 0){
                       close(fd);
                       return -1;
               }
       }
       snprint(buf, nbuf, "%s/%d", mtpt, conn);
       return fd;
}

static int
readstr(char *path, char *buf, int nbuf){
       int n, fd;

       n = 0;
       if((fd = open(path, OREAD)) >= 0){
               if((n = read(fd, buf, nbuf-1)) < 0)
                       n = 0;
               close(fd);
       }
       buf[n] = 0;
       return n;
}

int
urlpost(Url *url, char *ctype)
{
       char buf[1024];
       int n, fd;

       if((fd = webclone(url, buf, sizeof(buf))) < 0)
               return -1;
       if(ctype && *ctype)
               fprint(fd, "contenttype %s", ctype);
       n = strlen(buf);
       snprint(buf+n, sizeof(buf)-n, "/postbody");
       n = open(buf, OWRITE);
       close(fd);
       return n;
}

int
urlget(Url *url, int body)
{
       char buf[1024];
       int n, fd;

       if(body < 0){
               if((fd = dataget(url)) >= 0)
                       return fd;
               if((fd = fileget(url)) >= 0)
                       return fd;
               if((fd = webclone(url, buf, sizeof(buf))) < 0)
                       return -1;
       }else{
               char *x;

               if(fd2path(body, buf, sizeof(buf))){
                       close(body);
                       return -1;
               }
               if(x = strrchr(buf, '/'))
                       *x = 0;
               fd = open(buf, OREAD);
               close(body);
       }
       n = strlen(buf);
       snprint(buf+n, sizeof(buf)-n, "/body");
       body = open(buf, OREAD);
       close(fd);
       fd = body;
       if(fd < 0)
               return -1;

       snprint(buf+n, sizeof(buf)-n, "/parsed/url");
       readstr(buf, url->fullname, sizeof(url->fullname));

       snprint(buf+n, sizeof(buf)-n, "/parsed/fragment");
       readstr(buf, url->tag, sizeof(url->tag));

       snprint(buf+n, sizeof(buf)-n, "/contentencoding");
       readstr(buf, buf, sizeof(buf));

       if(!cistrcmp(buf, "compress"))
               fd = pipeline(fd, "exec uncompress");
       else if(!cistrcmp(buf, "gzip"))
               fd = pipeline(fd, "exec gunzip");
       else if(!cistrcmp(buf, "bzip2"))
               fd = pipeline(fd, "exec bunzip2");

       return fd;
}

int
urlresolve(Url *url)
{
       char buf[1024];
       int n, fd;

       if((fd = webclone(url, buf, sizeof(buf))) < 0)
               return -1;
       n = strlen(buf);
       snprint(buf+n, sizeof(buf)-n, "/parsed/url");
       readstr(buf, url->fullname, sizeof(url->fullname));
       snprint(buf+n, sizeof(buf)-n, "/parsed/fragment");
       readstr(buf, url->tag, sizeof(url->tag));
       close(fd);
       return 0;
}