package gzip

import (
   "compress/gzip"
   "errors"
   "fmt"
   "io"
   "log"
   "os"
   "path/filepath"
   "strings"
   "time"
   "utils"
)

func fileToDecompress(gzfile, file string) string {
   if file == "" {
      file = gzfile
   } else {
      dir, fileName := filepath.Split(file)
      if dir != "" {
         err := os.MkdirAll(dir, 0755)
         if err != nil {
            log.Println(err)
            return ""
         }
      }

      if fileName == "" {
         _, fileName = filepath.Split(gzfile)
      }
      file = filepath.Join(dir, fileName)
   }
   return strings.TrimSuffix(file, ".gz")
}

func fileToCompress(file, gzfile string) string {
   if gzfile == "" {
      gzfile = file
   } else {
      dir, fileName := filepath.Split(gzfile)
      if dir != "" {
         err := os.MkdirAll(dir, 0755)
         if err != nil {
            log.Println(err)
            return ""
         }
      }

      if fileName == "" {
         _, fileName = filepath.Split(file)
      }
      gzfile = filepath.Join(dir, fileName)
   }
   if strings.ToLower(filepath.Ext(gzfile)) != ".gz" {
      return gzfile + ".gz"
   } else {
      return gzfile
   }
}

//压缩文件
//file   待压缩的文件 如 path/pkg.tar
//gzfile 压缩后的文件 如 path/pkg.tar.gz OR path/  OR 为空
func Compress(file, gzfile string) error {
   if !utils.FileExists(file) {
      return errors.New(`File "` + file + `" not exist.`)
   }

   gzfile = fileToCompress(file, gzfile)
   if gzfile == "" {
      return errors.New(`Can not determine file name to save.`)
   }

   gzfile = utils.UNCPath(gzfile)
   file = utils.UNCPath(file)

   in, err := os.Open(file)
   defer in.Close()
   if err != nil {
      log.Println(err)
      return err
   }

   out, err := os.Create(gzfile)
   defer out.Close()
   if err != nil {
      log.Println(err)
      return err
   }

   //zw, err := gzip.NewWriterLevel(out, gzip.DefaultCompression)
   zw, err := gzip.NewWriterLevel(out, gzip.BestCompression)

   if err != nil {
      log.Println(err)
      return err
   }
   // Setting the Header fields is optional.
   zw.Name = filepath.Base(file)
   zw.Comment = "NONE"
   zw.ModTime = time.Now() //time.Date(1977, time.May, 25, 0, 0, 0, 0, time.UTC)

   //10M per read
   var buffer []byte = make([]byte, 10*1024*1024)
   for {
      size, err := in.Read(buffer)
      if err != nil {
         if size == 0 && err == io.EOF {
            break
         } else {
            log.Println(err)
            return err
         }
      }
      buffer = buffer[0:size]
      _, err = zw.Write(buffer)
      if err != nil {
         log.Println(err)
         return err
      }
   }

   if err := zw.Close(); err != nil {
      log.Println(err)
      return err
   }
   return nil
}

//解压缩文件
//gzfile   待解压缩的文件 如 path/pkg.tar.gz
//file     解压缩后的文件 如 path/pkg.tar OR path/  OR 为空
func Decompress(gzfile, file string) error {
   if !utils.FileExists(gzfile) {
      return errors.New(`File "` + gzfile + `" not exist.`)
   }

   if strings.ToLower(filepath.Ext(gzfile)) != ".gz" {
      return errors.New(`"` + gzfile + `" is not gzip file.`)
   }

   file = fileToDecompress(gzfile, file)
   if gzfile == "" {
      return errors.New(`Can not determine file name to save.`)
   }
   file = utils.UNCPath(file)
   gzfile = utils.UNCPath(gzfile)

   in, err := os.Open(gzfile)
   if err != nil {
      log.Println(err)
      return err
   }

   zr, err := gzip.NewReader(in)
   if err != nil {
      log.Println(err)
      return err
   }

   fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n\n", zr.Name, zr.Comment, zr.ModTime.UTC())

   out, err := os.Create(file)
   if err != nil {
      log.Println(err)
      return err
   }

   if _, err := io.Copy(out, zr); err != nil {
      log.Println(err)
      return err
   }

   if err := zr.Close(); err != nil {
      log.Println(err)
      return err
   }
   return nil
}