package main

import (
	"bufio"
	"fmt"
	"html/template"
	"net/http"
	"net/http/cgi"
	"os"
	"os/exec"
	"strings"
	"time"
)

type Result struct {
	Name    string
	Version string
	URL     string
	Suite   string
}

type ResultPage struct {
	Query      string
	Release    string
	NumResults int
	Time       string
	Results    []Result
}

var resTempl = `
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="./search.css" />
<title>Devuan Package information</title>
<style type="text/css">
code {font-weight: normal; 
              margin: 0 0px;
                            padding: 0px 0px;
                                          border: 1px solid #ffffff;
                                                        font-size: 95%; } 
</style>

<body>

    <div class="nav">
    <div class="leftfl">
      <a href="https://pkginfo.devuan.org" title="Devuan Package Information">
          <span>Home</span></a>
        <span class="separator">|</span>
      <a href="https://devuan.org" title="Devuan website">
          <span>Devuan</span></a>
        <span class="separator">|</span>
      <a href="https://git.devuan.org" title="Devuan gitlab">
          <span>Git</span></a>
        <span class="separator">|</span>
      <a href="https://devuan.org" title="Devuan BTS">
          <span>BTS</span></a>
        <span class="separator">|</span>
      <a href="https://dev1galaxy.org" title="dev1galaxy forum">
          <span>Forum</span></a>
        <span class="separator">|</span>
      <a href="https://popcon.devuan.org" title="Popularity Context">
          <span>Popcon</span></a>
   </div>

    <div class="rightfl-do">
  <a title="Please support Devuan development" class="button-do" href="https://devuan.org/os/donate">donate now!</a>
    </div>

    <div class="rightfl-dl">
  <a title="Download Devuan" class="button-dl" href="https://files.devuan.org/">download</a>
    </div>

  </div>


<div class="wrap">

<h1>Devuan Package information</h1>


<form method="GET" action="/cgi-bin/d1pkgweb-query">
Search Devuan Packages for: <input type="text" name="search"/>  in release 
<select name="release">
<option value="jessie">Jessie 1.0.0 (oldstable)</option>
<option value="ascii" selected>Ascii 2.0.0 (stable) </option>
<option value="beowulf" >Beowulf (testing)</option>
<option value="ceres" >Ceres (unstable)</option>
<option value="experimental" >Experimental</option>
<option value="any" >Any</option>
</select>
<input type="submit" value="Go!"/>
</form>


<h1>{{.NumResults}} results for <b>"{{.Query}}"</b> in {{.Release}} (in {{.Time}})  </h1>

<ul class="res_list">
{{range .Results}} 
<li class="res_item">
  <a href="{{.URL}}">[{{.Suite}}] {{.Name}}-{{.Version}}</a>
</li>
{{end}}
</div>

</div>

      <p style="margin-top:0px; margin-bottom:20px ; text-align: center;"> This site is a cookie-free zone</p>
      <div class="foot">                   
              <p id="copyright"  style="white-space: nowrap;">
                         Copyright (c) 2014-2018  <a href="https://www.dyne.org" data-rel="fiscal sponsor" 
                                 title="Learn about our fiscal sponsor">Dyne.org foundation</a>
                             <span></span>    
                                 <a rel="license" href="https://creativecommons.org/licenses/by-sa/4.0/" 
                             title="This work is licensed under a Creative Commons Attribution-ShareAlike 
                             4.0 International License.">CC-BY-SA 4.0 international</a></p>

                                                <p class="trademarks">
                                                Devuan is a registered trademark of the Dyne.org foundation.</p>
                                                <p class="trademarks" style="margin-top: -15px;">
                                                Debian is a registered trademark of  Software in the Public Interest, Inc. Linux is a registered trademark of Linus Torvalds.</p>
          </div>                     


</body>
</html>

`

var releaseMap = map[string]string{
	"jessie":       "index_jessie.txt",
	"ascii":        "index_ascii.txt",
	"beowulf":      "index_beowulf.txt",
	"ceres":        "index_ceres.txt",
	"experimental": "index_experimental.txt",
	"any":          "index.txt"}

func printError(errCode int, errMsg string) {

	fmt.Printf("Status:%d %s\r\n", errCode, errMsg)
	fmt.Printf("Content-Type: text/plain\r\n")
	fmt.Printf("\r\n%s\r\n", errMsg)
}

func parseLines(s string) []Result {

	results := make([]Result, 0, 10)

	scanner := bufio.NewScanner(strings.NewReader(s))
	for scanner.Scan() {
		URL := scanner.Text()
		URLParts := strings.Split(URL, "/")[1:]
		pkgNameVer := strings.Split(URLParts[len(URLParts)-1], ".html")[0]
		Name := strings.Split(pkgNameVer, "_")[0]
		Version := strings.Split(pkgNameVer, "_")[1]
		Suite := URLParts[2]
		results = append(results, Result{URL: URL, Name: Name, Version: Version, Suite: Suite})
	}
	//fmt.Printf("len(results): %d\n", resSize)
	return results
}

func pipeComands(commands []*exec.Cmd) ([]byte, error) {

	for i, command := range commands[:len(commands)-1] {
		out, err := command.StdoutPipe()
		if err != nil {
			return nil, err
		}
		command.Start()
		commands[i+1].Stdin = out
	}
	final, err := commands[len(commands)-1].Output()
	if err != nil {
		return nil, err
	}
	return final, nil

}

func getResults(req http.Request) (ResultPage, error) {

	var res ResultPage
	var release string

	req.ParseForm()

	searchQuery := req.Form["search"]
	if len(searchQuery) < 1 {
		printError(503, fmt.Sprintf("Something went wrong in parsing query...\r\n%s\r\n", req.Form))
		os.Exit(0)
	}
	res.Query = searchQuery[0]
	QueryTerms := strings.Split(res.Query, " ")

	selectedRelease := req.Form["release"]
	if len(selectedRelease) < 1 {
		release = "any"
	} else {
		release = selectedRelease[0]
	}

	res.Release = release
	fmt.Printf("QueryTerms: %s\n", QueryTerms)

	startTime := time.Now()

	commands := make([]*exec.Cmd, 0)

	cmd := "grep"
	args := []string{QueryTerms[0], releaseMap[release]}

	commands = append(commands, exec.Command(cmd, args...))

	for _, word := range QueryTerms[1:] {
		args = []string{word}
		fmt.Printf("word: %s\r\n", word)
		commands = append(commands, exec.Command(cmd, args...))
	}

	//if cmdOut, err := exec.Command(cmd, args...).Output(); err != nil {
	if cmdOut, err := pipeComands(commands); err != nil {
		fmt.Printf("error executing command: %s", err)
		res.Time = fmt.Sprintf("%s", time.Since(startTime))
		return res, nil
	} else {
		res.Results = parseLines(string(cmdOut[:len(cmdOut)]))
		res.NumResults = len(res.Results)
		res.Time = fmt.Sprintf("%s", time.Since(startTime))
	}
	return res, nil
}

func printResults(results ResultPage) {
	t, err := template.New("webpage").Parse(resTempl)

	if err != nil {
		printError(502, "Something went wrong...")
		return
	}

	fmt.Printf("Status: 200 OK\r\n")
	fmt.Printf("Content-Type: text/html\r\n")
	t.Execute(os.Stdout, results)

}

func main() {
	var req *http.Request
	var err error
	req, err = cgi.Request()
	if err != nil {
		printError(500, "cannot get requested resource"+err.Error())
		return
	}

	res, err := getResults(*req)
	if err != nil {
		printError(404, fmt.Sprintf("%s", err))
	} else {
		printResults(res)
	}

}