// FormatState takes a state and returns a string
func FormatState(s *terraform.State, c *colorstring.Colorize) string {
	if c == nil {
		panic("colorize not given")
	}

	if len(s.Resources) == 0 {
		return "The state file is empty. No resources are represented."
	}

	buf := new(bytes.Buffer)
	buf.WriteString("[reset]")

	// First get the names of all the resources so we can show them
	// in alphabetical order.
	names := make([]string, 0, len(s.Resources))
	for name, _ := range s.Resources {
		names = append(names, name)
	}
	sort.Strings(names)

	// Go through each resource and begin building up the output.
	for _, k := range names {
		rs := s.Resources[k]
		id := rs.ID
		if id == "" {
			id = "<not created>"
		}

		taintStr := ""
		if s.Tainted != nil {
			if _, ok := s.Tainted[k]; ok {
				taintStr = " (tainted)"
			}
		}

		buf.WriteString(fmt.Sprintf("%s:%s\n", k, taintStr))
		buf.WriteString(fmt.Sprintf("  id = %s\n", id))

		// Sort the attributes
		attrKeys := make([]string, 0, len(rs.Attributes))
		for ak, _ := range rs.Attributes {
			// Skip the id attribute since we just show the id directly
			if ak == "id" {
				continue
			}

			attrKeys = append(attrKeys, ak)
		}
		sort.Strings(attrKeys)

		// Output each attribute
		for _, ak := range attrKeys {
			av := rs.Attributes[ak]
			buf.WriteString(fmt.Sprintf("  %s = %s\n", ak, av))
		}
	}

	if len(s.Outputs) > 0 {
		buf.WriteString("\nOutputs:\n\n")

		// Sort the outputs
		ks := make([]string, 0, len(s.Outputs))
		for k, _ := range s.Outputs {
			ks = append(ks, k)
		}
		sort.Strings(ks)

		// Output each output k/v pair
		for _, k := range ks {
			v := s.Outputs[k]
			buf.WriteString(fmt.Sprintf("%s = %s\n", k, v))
		}
	}

	return c.Color(strings.TrimSpace(buf.String()))
}
// FormatPlan takes a plan and returns a
func FormatPlan(p *terraform.Plan, c *colorstring.Colorize) string {
	if p.Diff == nil || p.Diff.Empty() {
		return "This plan does nothing."
	}

	if c == nil {
		c = &colorstring.Colorize{
			Colors: colorstring.DefaultColors,
			Reset:  false,
		}
	}

	buf := new(bytes.Buffer)

	// We want to output the resources in sorted order to make things
	// easier to scan through, so get all the resource names and sort them.
	names := make([]string, 0, len(p.Diff.Resources))
	for name, _ := range p.Diff.Resources {
		names = append(names, name)
	}
	sort.Strings(names)

	// Go through each sorted name and start building the output
	for _, name := range names {
		rdiff := p.Diff.Resources[name]

		// Determine the color for the text (green for adding, yellow
		// for change, red for delete), and symbol, and output the
		// resource header.
		color := "yellow"
		symbol := "~"
		if rdiff.RequiresNew() && rdiff.Destroy {
			color = "green"
			symbol = "-/+"
		} else if rdiff.RequiresNew() {
			color = "green"
			symbol = "+"
		} else if rdiff.Destroy {
			color = "red"
			symbol = "-"
		}
		buf.WriteString(c.Color(fmt.Sprintf(
			"[%s]%s %s\n",
			color, symbol, name)))

		// Get all the attributes that are changing, and sort them. Also
		// determine the longest key so that we can align them all.
		keyLen := 0
		keys := make([]string, 0, len(rdiff.Attributes))
		for key, _ := range rdiff.Attributes {
			// Skip the ID since we do that specially
			if key == "id" {
				continue
			}

			keys = append(keys, key)
			if len(key) > keyLen {
				keyLen = len(key)
			}
		}
		sort.Strings(keys)

		// Go through and output each attribute
		for _, attrK := range keys {
			attrDiff := rdiff.Attributes[attrK]

			v := attrDiff.New
			if attrDiff.NewComputed {
				v = "<computed>"
			}

			newResource := ""
			if attrDiff.RequiresNew && rdiff.Destroy {
				newResource = " (forces new resource)"
			}

			buf.WriteString(fmt.Sprintf(
				"    %s:%s %#v => %#v%s\n",
				attrK,
				strings.Repeat(" ", keyLen-len(attrK)),
				attrDiff.Old,
				v,
				newResource))
		}

		// Write the reset color so we don't overload the user's terminal
		buf.WriteString(c.Color("[reset]\n"))
	}

	return strings.TrimSpace(buf.String())
}