package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"image"
	"image/color"
	"image/draw"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io/ioutil"
	"log"
	"net/http"

	"code.google.com/p/rsc/qr"
	"code.google.com/p/rsc/qr/web/resize"
	"github.com/golang/freetype"
	"github.com/golang/freetype/truetype"
	"golang.org/x/image/bmp"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
)

type circle struct {
	p image.Point
	r int
}

func (c *circle) ColorModel() color.Model {
	return color.AlphaModel
}

func (c *circle) Bounds() image.Rectangle {
	return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
}

func (c *circle) At(x, y int) color.Color {
	xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
	if xx*xx+yy*yy < rr*rr {
		return color.Alpha{255}
	}
	return color.Alpha{0}
}

var (
	// bgImage 漂亮的背景
	bgImage = getNetImage("http://olcd71ai5.bkt.clouddn.com/qr/bg.png")

	// fontFile 字体文件
	fontFile = "config/Dengl.ttf"

	// fontSize 字体尺寸
	fontSize float64 = 18

	// fontDPI 屏幕每英寸的分辨率
	fontDPI float64 = 72

	// font 字体
	fontType *truetype.Font
)

func init() {
	fontBytes, err := ioutil.ReadFile(fontFile)
	if err != nil {
		panic(err)
	}
	fontType, err = freetype.ParseFont(fontBytes)
	if err != nil {
		panic(err)
	}
}

func main() {
	http.HandleFunc("/qr", qrImage)
	fmt.Println(http.ListenAndServe(":8080", nil))
}

func qrImage(w http.ResponseWriter, req *http.Request) {
	content := req.FormValue("data")
	data, err := base64.StdEncoding.DecodeString(content)
	if err != nil {
		log.Println(err)
		return
	}

	v := struct {
		URL      string `json:"url"`
		HeadURL  string `json:"headurl"`
		NickName string `json:"nickname"`
	}{}
	json.Unmarshal(data, &v)
	sx, sy, width := 110, 915, 120
	qrCode, _ := qr.Encode(v.URL, qr.L)
	pngData := qrCode.PNG()
	imgQrPng, _ := png.Decode(bytes.NewReader(pngData))
	imgQrPng = resize.Resample(imgQrPng, imgQrPng.Bounds(), width, width)
	qrBounds := imgQrPng.Bounds()
	qrDx := qrBounds.Dx()
	qrDy := qrBounds.Dy()

	img := image.NewRGBA(bgImage.Bounds())
	draw.Draw(img, bgImage.Bounds(), bgImage, image.Pt(0, 0), draw.Src)

	for x := 0; x < qrDx; x++ {
		for y := 0; y < qrDy; y++ {
			qrColor := imgQrPng.At(x, y)
			r, g, b, _ := qrColor.RGBA()
			if r == 0 || g == 0 || b == 0 {
				img.Set(sx+x, sy+y, qrColor)
			}
		}
	}

	if v.HeadURL != "" {
		headImage := getNetImage(v.HeadURL)
		headImage = resize.Resample(headImage, headImage.Bounds(), 100, 100)
		sp := image.Pt(250, 80)
		rect := headImage.Bounds().Add(sp)
		draw.DrawMask(img, rect, headImage, image.ZP, &circle{image.Pt(50, 50), 50}, image.ZP, draw.Over)
	}

	if v.NickName != "" {
		d := &font.Drawer{
			Dst: img,
			Src: image.NewUniform(color.RGBA{0xff, 0x00, 0x00, 0xff}),
			Face: truetype.NewFace(fontType, &truetype.Options{
				Size:    fontSize,
				DPI:     fontDPI,
				Hinting: font.HintingNone,
			}),
		}

		d.Dot = fixed.Point26_6{
			X: (fixed.I(600) - d.MeasureString(v.NickName)) / 2,
			Y: fixed.I(205),
		}
		d.DrawString(v.NickName)
	}

	w.Header().Set("Content-Type", "image/jpeg")
	jpeg.Encode(w, img, &jpeg.Options{Quality: 90})
}

func getNetImage(url string) image.Image {
	resp, err := http.Get(url)
	if err != nil {
		log.Println(err)
		return image.NewNRGBA(image.Rect(0, 0, 600, 400))
	}
	defer resp.Body.Close()
	data, _ := ioutil.ReadAll(resp.Body)
	contentType := http.DetectContentType(data)
	var imgBG image.Image
	if contentType == "image/png" {
		imgBG, err = png.Decode(bytes.NewReader(data))
	} else if contentType == "image/jpeg" {
		imgBG, err = jpeg.Decode(bytes.NewReader(data))
	} else if contentType == "image/gif" {
		imgBG, err = gif.Decode(bytes.NewReader(data))
	} else if contentType == "image/bmp" {
		imgBG, err = bmp.Decode(bytes.NewReader(data))
	}
	if err != nil {
		log.Println(err)
		return image.NewNRGBA(image.Rect(0, 0, 600, 400))
	}
	return imgBG
}