func (g *Container) ArrayCount(hierarchy ...string) (int, error) {
	if array, ok := g.Search(hierarchy...).Data().([]interface{}); ok {
		return len(array), nil
	}
	return 0, ErrNotArray
}
ArrayCount counts the number of elements in a JSON array at a path.
package gabs
import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"strconv"
	"strings"
)
var (
	ErrOutOfBounds = errors.New("out of bounds")
	ErrNotObjOrArray = errors.New("not an object or array")
	ErrNotObj = errors.New("not an object")
	ErrInvalidQuery = errors.New("invalid search query")
	ErrNotArray = errors.New("not an array")
	ErrPathCollision = errors.New("encountered value collision whilst building path")
	ErrInvalidInputObj = errors.New("invalid input object")
	ErrInvalidInputText = errors.New("input text could not be parsed")
	ErrNotFound = errors.New("field not found")
	ErrInvalidPath = errors.New("invalid file path")
	ErrInvalidBuffer = errors.New("input buffer contained invalid JSON")
)
func JSONPointerToSlice(path string) ([]string, error) {
	if len(path) < 1 {
		return nil, errors.New("failed to resolve JSON pointer: path must not be empty")
	}
	if path[0] != '/' {
		return nil, errors.New("failed to resolve JSON pointer: path must begin with '/'")
	}
	hierarchy := strings.Split(path, "/")[1:]
	for i, v := range hierarchy {
		v = strings.Replace(v, "~1", "/", -1)
		v = strings.Replace(v, "~0", "~", -1)
		hierarchy[i] = v
	}
	return hierarchy, nil
}
func DotPathToSlice(path string) []string {
	hierarchy := strings.Split(path, ".")
	for i, v := range hierarchy {
		v = strings.Replace(v, "~1", ".", -1)
		v = strings.Replace(v, "~0", "~", -1)
		hierarchy[i] = v
	}
	return hierarchy
}
type Container struct {
	object interface{}
}
func (g *Container) Data() interface{} {
	if g == nil {
		return nil
	}
	return g.object
}
func (g *Container) searchStrict(allowWildcard bool, hierarchy ...string) (*Container, error) {
	object := g.Data()
	for target := 0; target < len(hierarchy); target++ {
		pathSeg := hierarchy[target]
		if mmap, ok := object.(map[string]interface{}); ok {
			object, ok = mmap[pathSeg]
			if !ok {
				return nil, fmt.Errorf("failed to resolve path segment '%v': key '%v' was not found", target, pathSeg)
			}
		} else if marray, ok := object.([]interface{}); ok {
			if allowWildcard && pathSeg == "*" {
				tmpArray := []interface{}{}
				for _, val := range marray {
					if (target + 1) >= len(hierarchy) {
						tmpArray = append(tmpArray, val)
					} else if res := Wrap(val).Search(hierarchy[target+1:]...); res != nil {
						tmpArray = append(tmpArray, res.Data())
					}
				}
				if len(tmpArray) == 0 {
					return nil, nil
				}
				return &Container{tmpArray}, nil
			}
			index, err := strconv.Atoi(pathSeg)
			if err != nil {
				return nil, fmt.Errorf("failed to resolve path segment '%v': found array but segment value '%v' could not be parsed into array index: %v", target, pathSeg, err)
			}
			if index < 0 {
				return nil, fmt.Errorf("failed to resolve path segment '%v': found array but index '%v' is invalid", target, pathSeg)
			}
			if len(marray) <= index {
				return nil, fmt.Errorf("failed to resolve path segment '%v': found array but index '%v' exceeded target array size of '%v'", target, pathSeg, len(marray))
			}
			object = marray[index]
		} else {
			return nil, fmt.Errorf("failed to resolve path segment '%v': field '%v' was not found", target, pathSeg)
		}
	}
	return &Container{object}, nil
}
func (g *Container) Search(hierarchy ...string) *Container {
	c, _ := g.searchStrict(true, hierarchy...)
	return c
}
func (g *Container) Path(path string) *Container {
	return g.Search(DotPathToSlice(path)...)
}
func (g *Container) JSONPointer(path string) (*Container, error) {
	hierarchy, err := JSONPointerToSlice(path)
	if err != nil {
		return nil, err
	}
	return g.searchStrict(false, hierarchy...)
}
func (g *Container) S(hierarchy ...string) *Container {
	return g.Search(hierarchy...)
}
func (g *Container) Exists(hierarchy ...string) bool {
	return g.Search(hierarchy...) != nil
}
func (g *Container) ExistsP(path string) bool {
	return g.Exists(DotPathToSlice(path)...)
}
func (g *Container) Index(index int) *Container {
	if array, ok := g.Data().([]interface{}); ok {
		if index >= len(array) {
			return nil
		}
		return &Container{array[index]}
	}
	return nil
}
func (g *Container) Children() []*Container {
	if array, ok := g.Data().([]interface{}); ok {
		children := make([]*Container, len(array))
		for i := 0; i < len(array); i++ {
			children[i] = &Container{array[i]}
		}
		return children
	}
	if mmap, ok := g.Data().(map[string]interface{}); ok {
		children := []*Container{}
		for _, obj := range mmap {
			children = append(children, &Container{obj})
		}
		return children
	}
	return nil
}
func (g *Container) ChildrenMap() map[string]*Container {
	if mmap, ok := g.Data().(map[string]interface{}); ok {
		children := make(map[string]*Container, len(mmap))
		for name, obj := range mmap {
			children[name] = &Container{obj}
		}
		return children
	}
	return map[string]*Container{}
}
func (g *Container) Set(value interface{}, hierarchy ...string) (*Container, error) {
	if g == nil {
		return nil, errors.New("failed to resolve path, container is nil")
	}
	if len(hierarchy) == 0 {
		g.object = value
		return g, nil
	}
	if g.object == nil {
		g.object = map[string]interface{}{}
	}
	object := g.object
	for target := 0; target < len(hierarchy); target++ {
		pathSeg := hierarchy[target]
		if mmap, ok := object.(map[string]interface{}); ok {
			if target == len(hierarchy)-1 {
				object = value
				mmap[pathSeg] = object
			} else if object = mmap[pathSeg]; object == nil {
				mmap[pathSeg] = map[string]interface{}{}
				object = mmap[pathSeg]
			}
		} else if marray, ok := object.([]interface{}); ok {
			if pathSeg == "-" {
				if target < 1 {
					return nil, errors.New("unable to append new array index at root of path")
				}
				if target == len(hierarchy)-1 {
					object = value
				} else {
					object = map[string]interface{}{}
				}
				marray = append(marray, object)
				if _, err := g.Set(marray, hierarchy[:target]...); err != nil {
					return nil, err
				}
			} else {
				index, err := strconv.Atoi(pathSeg)
				if err != nil {
					return nil, fmt.Errorf("failed to resolve path segment '%v': found array but segment value '%v' could not be parsed into array index: %v", target, pathSeg, err)
				}
				if index < 0 {
					return nil, fmt.Errorf("failed to resolve path segment '%v': found array but index '%v' is invalid", target, pathSeg)
				}
				if len(marray) <= index {
					return nil, fmt.Errorf("failed to resolve path segment '%v': found array but index '%v' exceeded target array size of '%v'", target, pathSeg, len(marray))
				}
				if target == len(hierarchy)-1 {
					object = value
					marray[index] = object
				} else if object = marray[index]; object == nil {
					return nil, fmt.Errorf("failed to resolve path segment '%v': field '%v' was not found", target, pathSeg)
				}
			}
		} else {
			return nil, ErrPathCollision
		}
	}
	return &Container{object}, nil
}
func (g *Container) SetP(value interface{}, path string) (*Container, error) {
	return g.Set(value, DotPathToSlice(path)...)
}
func (g *Container) SetIndex(value interface{}, index int) (*Container, error) {
	if array, ok := g.Data().([]interface{}); ok {
		if index >= len(array) {
			return nil, ErrOutOfBounds
		}
		array[index] = value
		return &Container{array[index]}, nil
	}
	return nil, ErrNotArray
}
func (g *Container) SetJSONPointer(value interface{}, path string) (*Container, error) {
	hierarchy, err := JSONPointerToSlice(path)
	if err != nil {
		return nil, err
	}
	return g.Set(value, hierarchy...)
}
func (g *Container) Object(hierarchy ...string) (*Container, error) {
	return g.Set(map[string]interface{}{}, hierarchy...)
}
func (g *Container) ObjectP(path string) (*Container, error) {
	return g.Object(DotPathToSlice(path)...)
}
func (g *Container) ObjectI(index int) (*Container, error) {
	return g.SetIndex(map[string]interface{}{}, index)
}
func (g *Container) Array(hierarchy ...string) (*Container, error) {
	return g.Set([]interface{}{}, hierarchy...)
}
func (g *Container) ArrayP(path string) (*Container, error) {
	return g.Array(DotPathToSlice(path)...)
}
func (g *Container) ArrayI(index int) (*Container, error) {
	return g.SetIndex([]interface{}{}, index)
}
func (g *Container) ArrayOfSize(size int, hierarchy ...string) (*Container, error) {
	a := make([]interface{}, size)
	return g.Set(a, hierarchy...)
}
func (g *Container) ArrayOfSizeP(size int, path string) (*Container, error) {
	return g.ArrayOfSize(size, DotPathToSlice(path)...)
}
func (g *Container) ArrayOfSizeI(size, index int) (*Container, error) {
	a := make([]interface{}, size)
	return g.SetIndex(a, index)
}
func (g *Container) Delete(hierarchy ...string) error {
	if g == nil || g.object == nil {
		return ErrNotObj
	}
	if len(hierarchy) == 0 {
		return ErrInvalidQuery
	}
	object := g.object
	target := hierarchy[len(hierarchy)-1]
	if len(hierarchy) > 1 {
		object = g.Search(hierarchy[:len(hierarchy)-1]...).Data()
	}
	if obj, ok := object.(map[string]interface{}); ok {
		if _, ok = obj[target]; !ok {
			return ErrNotFound
		}
		delete(obj, target)
		return nil
	}
	if array, ok := object.([]interface{}); ok {
		if len(hierarchy) < 2 {
			return errors.New("unable to delete array index at root of path")
		}
		index, err := strconv.Atoi(target)
		if err != nil {
			return fmt.Errorf("failed to parse array index '%v': %v", target, err)
		}
		if index >= len(array) {
			return ErrOutOfBounds
		}
		if index < 0 {
			return ErrOutOfBounds
		}
		array = append(array[:index], array[index+1:]...)
		g.Set(array, hierarchy[:len(hierarchy)-1]...)
		return nil
	}
	return ErrNotObjOrArray
}
func (g *Container) DeleteP(path string) error {
	return g.Delete(DotPathToSlice(path)...)
}
func (g *Container) MergeFn(source *Container, collisionFn func(destination, source interface{}) interface{}) error {
	var recursiveFnc func(map[string]interface{}, []string) error
	recursiveFnc = func(mmap map[string]interface{}, path []string) error {
		for key, value := range mmap {
			newPath := append(path, key)
			if g.Exists(newPath...) {
				existingData := g.Search(newPath...).Data()
				switch t := value.(type) {
				case map[string]interface{}:
					switch existingVal := existingData.(type) {
					case map[string]interface{}:
						if err := recursiveFnc(t, newPath); err != nil {
							return err
						}
					default:
						if _, err := g.Set(collisionFn(existingVal, t), newPath...); err != nil {
							return err
						}
					}
				default:
					if _, err := g.Set(collisionFn(existingData, t), newPath...); err != nil {
						return err
					}
				}
			} else {
				if _, err := g.Set(value, newPath...); err != nil {
					return err
				}
			}
		}
		return nil
	}
	if mmap, ok := source.Data().(map[string]interface{}); ok {
		return recursiveFnc(mmap, []string{})
	}
	return nil
}
func (g *Container) Merge(source *Container) error {
	return g.MergeFn(source, func(dest, source interface{}) interface{} {
		destArr, destIsArray := dest.([]interface{})
		sourceArr, sourceIsArray := source.([]interface{})
		if destIsArray {
			if sourceIsArray {
				return append(destArr, sourceArr...)
			}
			return append(destArr, source)
		}
		if sourceIsArray {
			return append(append([]interface{}{}, dest), sourceArr...)
		}
		return []interface{}{dest, source}
	})
}
func (g *Container) ArrayAppend(value interface{}, hierarchy ...string) error {
	if array, ok := g.Search(hierarchy...).Data().([]interface{}); ok {
		array = append(array, value)
		_, err := g.Set(array, hierarchy...)
		return err
	}
	newArray := []interface{}{}
	if d := g.Search(hierarchy...).Data(); d != nil {
		newArray = append(newArray, d)
	}
	newArray = append(newArray, value)
	_, err := g.Set(newArray, hierarchy...)
	return err
}
func (g *Container) ArrayAppendP(value interface{}, path string) error {
	return g.ArrayAppend(value, DotPathToSlice(path)...)
}
func (g *Container) ArrayConcat(value interface{}, hierarchy ...string) error {
	var array []interface{}
	if d := g.Search(hierarchy...).Data(); d != nil {
		if targetArray, ok := d.([]interface{}); !ok {
			array = append(array, d)
		} else {
			array = targetArray
		}
	}
	switch v := value.(type) {
	case []interface{}:
		array = append(array, v...)
	default:
		array = append(array, v)
	}
	_, err := g.Set(array, hierarchy...)
	return err
}
func (g *Container) ArrayConcatP(value interface{}, path string) error {
	return g.ArrayConcat(value, DotPathToSlice(path)...)
}
func (g *Container) ArrayRemove(index int, hierarchy ...string) error {
	if index < 0 {
		return ErrOutOfBounds
	}
	array, ok := g.Search(hierarchy...).Data().([]interface{})
	if !ok {
		return ErrNotArray
	}
	if index < len(array) {
		array = append(array[:index], array[index+1:]...)
	} else {
		return ErrOutOfBounds
	}
	_, err := g.Set(array, hierarchy...)
	return err
}
func (g *Container) ArrayRemoveP(index int, path string) error {
	return g.ArrayRemove(index, DotPathToSlice(path)...)
}
func (g *Container) ArrayElement(index int, hierarchy ...string) (*Container, error) {
	if index < 0 {
		return nil, ErrOutOfBounds
	}
	array, ok := g.Search(hierarchy...).Data().([]interface{})
	if !ok {
		return nil, ErrNotArray
	}
	if index < len(array) {
		return &Container{array[index]}, nil
	}
	return nil, ErrOutOfBounds
}
func (g *Container) ArrayElementP(index int, path string) (*Container, error) {
	return g.ArrayElement(index, DotPathToSlice(path)...)
}