package HtmlTools

import (
	"fmt"
	"golang.org/x/net/html"
	"log"
	"net/http"
)

func GetHtml() *html.Node {
	resp, err := http.Get("https://golang-china.github.io/gopl-zh/ch5/ch5-02.html")
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		err := resp.Body.Close()
		if err != nil {
			log.Fatal(err)
			return nil
		}
	}
	doc, err := html.Parse(resp.Body)
	if err != nil {
		log.Fatal(err)
		return nil
	}
	return doc

}
func GetHtmlResponse(url string) (*html.Node, *http.Response) {
	// 检查参数
	if url == "" {
		url = "https://go.dev/"
	}
	resp, err := http.Get("https://go.dev/")
	if err != nil {
		log.Fatal(err)
	}
	if resp.StatusCode != http.StatusOK {
		err := resp.Body.Close()
		if err != nil {
			log.Fatal(err)
			return nil, nil
		}
	}
	doc, err := html.Parse(resp.Body)
	if err != nil {
		log.Fatal(err)
		return nil, nil
	}
	return doc, resp

}

// ForEachNode 深度遍历 n, pre和post分别表示压栈和出栈时执行的动作
//
//	n			*html.Node
//	pre			func(n *html.Node)
//	post		func(n *html.Node)
//
// 将 ForEachNode() 移动到单独的软件包，供以后方便调用
func ForEachNode(n *html.Node, pre, post func(n *html.Node)) {
	if n == nil {
		return
	}
	if pre != nil {
		pre(n)
	}
	//for c := n.FirstChild; c != nil; c = c.NextSibling {
	//	forEachNode(c, pre, post)
	//}
	ForEachNode(n.FirstChild, pre, post)
	ForEachNode(n.NextSibling, pre, post)
	if post != nil {
		post(n)
	}
}

// Extract
//
//	 现在links中存储的不是href属性的原始值，
//	 而是通过resp.Request.URL解析后的值。
//	 解析后，这些连接以绝对路径的形式存在，可以直接被http.Get访问。
//
//		return	 	[]string, error
//
// 将Extract()移动到单独的软件包，供以后方便调用
func Extract() ([]string, error) {
	node, resp := GetHtmlResponse("")
	var links []string
	visitNode := func(n *html.Node) {
		if n.Type == html.ElementNode && n.Data == "a" {
			for _, a := range n.Attr {
				if a.Key != "href" {
					continue
				}
				// 将相对路径和url的内容组合在一起形成完整的绝对路径
				link, err := resp.Request.URL.Parse(a.Val)
				if err != nil {
					// 忽略掉报error的URL
					fmt.Println(err)
					continue
				}
				// 将link添加到切片
				links = append(links, link.String())
			}
		}
	}
	ForEachNode(node, visitNode, nil)
	return links, nil
}
