package main

import (
	"Study/src/study/day7Function/HtmlTools"
	"bytes"
	"fmt"
	"golang.org/x/net/html"
	"io"
)

func ElementsByTagName(doc *html.Node, name ...string) []*html.Node {
	// 创建一个map, 用于保存传入的tag name和是否已被找到的状态
	tags := make(map[string]bool)
	for _, tag := range name {
		tags[tag] = false
	}
	// 创建用于保存查找到的元素的切片
	var elements []*html.Node
	// 声明查找函数
	var visit func(*html.Node)
	visit = func(n *html.Node) {
		// 如果当前节点是html元素节点
		if n.Type == html.ElementNode {
			// 检测tags中是否存在 n.Data
			// 该版本为只返回找到的第一个节点node
			// 如果要找到doc节点下所有的符合条件的node的话
			// 请打开下面这行代码, 这行代码表示只会检查tags map里是否存在n.Data
			//if _, ok := tags[n.Data]; ok {
			// 并注释掉下面的这一行代码, 这行表示会同时检查是否存在和是否添加过同名节点
			if isFind, ok := tags[n.Data]; ok && !isFind {
				// 将该元素加入到结果切片中
				elements = append(elements, n)
				// 标记该tag name已被查找到
				tags[n.Data] = true
			}
		}
		// 递归查找子节点
		for c := n.FirstChild; c != nil; c = c.NextSibling {
			visit(c)
		}
	}
	// 从传入的文档节点开始查找
	visit(doc)
	// 返回查找到的元素切片
	return elements
}

func main() {
	doc := HtmlTools.GetHtml()
	images := ElementsByTagName(doc, "img")
	headings := ElementsByTagName(doc, "h1", "h2", "h3", "h4", "a", "div")
	for _, v := range images {
		fmt.Println(v.Data)
	}
	fmt.Println()
	for _, v := range headings {
		fmt.Println(v.Data)
	}

	//⚠️当需要检测一个mao中是否存在某一元素时，使用以下代码
	//  v, ok := m2["a"]
	//  v 是 这个map["a"]的值 即 v == m2["a"]
	//  ok是一个bool值, 当m2这个map存在a这个元素时, ok值为true, 反之则为false
	m2 := make(map[string]any)
	m2["a"] = "aaa"
	m2["b"] = "bbb"
	m2["c"] = "ccc"
	v, ok := m2["a"]
	fmt.Println("a  ", ok, v) // true, aaa
	_, ok = m2["b"]
	fmt.Println("b  ", ok) // true
	_, ok = m2["c"]
	fmt.Println("c  ", ok) // true
	_, ok = m2["d"]
	fmt.Println("d  ", ok) // false
	_, ok = m2["e"]
	fmt.Println("e  ", ok) // false
	_, ok = m2["f"]
	fmt.Println("f  ", ok) // false

	var buf *bytes.Buffer
	//fmt.Printf("buf: \t(%T, %[1]v)\n", buf)
	f(buf)
}

// If out is non-nil, output will be written to it.
func f(out io.Writer) {
	// ...do something...
	var a *bytes.Buffer // 结构体空指针
	var b io.Writer     // io.write 接口
	var c interface{}   // 空接口
	var d io.Writer = a

	fmt.Printf("a: \t(%T, %[1]v)\n", a)
	fmt.Printf("b: \t(%T, %[1]v)\n", b)
	fmt.Printf("c: \t(%T, %[1]v)\n", c)
	fmt.Printf("d: \t(%T, %[1]v)\n", d)
	fmt.Printf("out: \t(%T, %[1]v)\n", out)

	fmt.Println()
	fmt.Println("a == b", a == b)
	fmt.Println("a == c", a == c)
	fmt.Println("a == d", a == d)
	fmt.Println("a == out", a == out)
	fmt.Println("a == nil", a == nil)
	fmt.Println()
	fmt.Println("b == c", b == c)
	fmt.Println("b == d", b == d)
	fmt.Println("b == out", b == out)
	fmt.Println("b == nil", b == nil)
	fmt.Println()
	fmt.Println("c == d", c == d)
	fmt.Println("c == out", c == out)
	fmt.Println("c == nil", c == nil)
	fmt.Println()
	fmt.Println("d == out", d == out)
	fmt.Println("d == nil", d == nil)

	fmt.Println("out == nil", out == nil)
	if out != a {
		fmt.Fprintf(out, "Hello, %s!\n", "world")
		//fmt.Printf("(%T, %[1]v)\n", out)
	}
}
