package matrix

import (
	"errors"
	"strconv"
	"strings"
)

// Matrix is a grid of ints
type Matrix struct {
	vals [][]int
}

// New creates a new Matrix from a string of numbers
func New(in string) (*Matrix, error) {
	ret := Matrix{}
	rows := strings.Split(in, "\n")
	for i := range rows {
		flds := strings.Fields(rows[i])
		var ints []int
		for j := range flds {
			if v, err := strconv.Atoi(flds[j]); err != nil {
				return &ret, err
			} else {
				ints = append(ints, v)
			}
		}
		ret.vals = append(ret.vals, ints)
	}
	numInRow := -1
	for i := range ret.vals {
		if numInRow != -1 {
			if len(ret.vals[i]) != numInRow {
				return &ret, errors.New("All rows must be equal length")
			}
		}
		numInRow = len(ret.vals[i])
	}
	return &ret, nil
}

// Rows returns the values of the rows in the matrix
func (m *Matrix) Rows() [][]int {
	var ret [][]int
	for i := range m.vals {
		var row []int
		for j := range m.vals[i] {
			row = append(row, m.vals[i][j])
		}
		ret = append(ret, row)
	}
	return ret
}

// Cols returns the values of the cols in the matrix
func (m *Matrix) Cols() [][]int {
	var ret [][]int
	for i := range m.vals[0] {
		var row []int
		for j := range m.vals {
			row = append(row, m.vals[j][i])
		}
		ret = append(ret, row)
	}
	return ret
}

// Set sets the value at r,c to val
func (m *Matrix) Set(r, c int, val int) bool {
	if r < 0 || c < 0 {
		return false
	}
	if len(m.vals) <= r || len(m.vals[r]) <= c {
		return false
	}
	m.vals[r][c] = val
	return true
}
