func (usr *User) DeleteMeta(attr string) (*MetaCollection, error) {
	if mc, err := usr.Meta(); err == nil {
		return mc, mc.Delete(attr)
	} else {
		return nil, err
	}
}
DeleteMeta deletes a single Meta triple struct, identified by Attribute field
package gorods
import "C"
import (
	"fmt"
	"strconv"
	"strings"
	"time"
	"unsafe"
)
type User struct {
	name        string
	zone        *Zone
	createTime  time.Time
	modifyTime  time.Time
	id          int
	typ         int
	info        string
	comment     string
	parentSlice *Users
	hasInit bool
	groups Groups
	con    *Connection
	metaCol *MetaCollection
}
type Users []*User
func initUser(name string, zone *Zone, con *Connection) (*User, error) {
	usr := new(User)
	usr.name = name
	usr.zone = zone
	usr.con = con
	return usr, nil
}
func (usr *User) Remove() bool {
	for n, p := range *usr.parentSlice {
		if p.name == usr.name {
			usr.parentSlice.Remove(n)
			return true
		}
	}
	return false
}
func (usr *User) Name() string {
	return usr.name
}
func (usr *User) Path() string {
	return usr.name
}
func (usr *User) Zone() *Zone {
	return usr.zone
}
func (usr *User) Comment() (string, error) {
	if err := usr.init(); err != nil {
		return usr.comment, err
	}
	return usr.comment, nil
}
func (usr *User) Info() (string, error) {
	if err := usr.init(); err != nil {
		return usr.info, err
	}
	return usr.info, nil
}
func (usr *User) CreateTime() (time.Time, error) {
	if err := usr.init(); err != nil {
		return usr.createTime, err
	}
	return usr.createTime, nil
}
func (usr *User) ModifyTime() (time.Time, error) {
	if err := usr.init(); err != nil {
		return usr.modifyTime, err
	}
	return usr.modifyTime, nil
}
func (usr *User) Id() (int, error) {
	if err := usr.init(); err != nil {
		return usr.id, err
	}
	return usr.id, nil
}
func (usr *User) Type() int {
	if err := usr.init(); err != nil {
		return UnknownType
	}
	return usr.typ
}
func (usr *User) Con() *Connection {
	return usr.con
}
func (usr *User) Groups() (Groups, error) {
	if err := usr.init(); err != nil {
		return nil, err
	}
	return usr.groups, nil
}
func (usr *User) Delete() error {
	if err := deleteUser(usr.Name(), usr.Zone(), usr.con); err != nil {
		return err
	}
	if err := usr.con.RefreshUsers(); err != nil {
		return err
	}
	return nil
}
func (usr *User) init() error {
	if !usr.hasInit {
		if err := usr.RefreshInfo(); err != nil {
			return err
		}
		if err := usr.RefreshGroups(); err != nil {
			return err
		}
		usr.hasInit = true
	}
	return nil
}
func (usr *User) RefreshInfo() error {
	typeMap := map[string]int{
		"rodsuser":   UserType,
		"rodsadmin":  AdminType,
		"groupadmin": GroupAdminType,
	}
	if infoMap, err := usr.FetchInfo(); err == nil {
		usr.comment = infoMap["r_comment"]
		usr.createTime = timeStringToTime(infoMap["create_ts"])
		usr.modifyTime = timeStringToTime(infoMap["modify_ts"])
		usr.id, _ = strconv.Atoi(infoMap["user_id"])
		usr.typ = typeMap[infoMap["user_type_name"]]
		usr.info = infoMap["user_info"]
		if zones, err := usr.con.Zones(); err != nil {
			return err
		} else {
			if zne := zones.FindByName(infoMap["zone_name"], usr.con); zne != nil {
				usr.zone = zne
			} else {
				return newError(Fatal, -1, fmt.Sprintf("iRODS Refresh User Info Failed: Unable to locate zone in cache"))
			}
		}
	} else {
		return err
	}
	return nil
}
func (usr *User) RefreshGroups() error {
	if grps, err := usr.FetchGroups(); err == nil {
		usr.groups = grps
	} else {
		return err
	}
	return nil
}
func (usrs Users) FindByName(name string, con *Connection) *User {
	for _, usr := range usrs {
		if usr.name == name {
			return usr
		}
	}
	zne, err := con.LocalZone()
	if err != nil {
		return nil
	}
	usr, _ := initUser(name, zne, con)
	return usr
}
func (usrs *Users) Remove(index int) {
	*usrs = append((*usrs)[:index], (*usrs)[index+1:]...)
}
func (usr *User) String() string {
	usr.init()
	return fmt.Sprintf("%v:%v#%v", getTypeString(usr.typ), usr.name, usr.zone)
}
func (usr *User) FetchGroups() (Groups, error) {
	var (
		result C.goRodsStringResult_t
		err    *C.char
	)
	cName := C.CString(usr.name)
	defer C.free(unsafe.Pointer(cName))
	result.size = C.int(0)
	ccon := usr.con.GetCcon()
	if status := C.gorods_get_user_groups(ccon, cName, &result, &err); status != 0 {
		usr.con.ReturnCcon(ccon)
		return nil, newError(Fatal, status, fmt.Sprintf("iRODS Get Groups Failed: %v", C.GoString(err)))
	}
	usr.con.ReturnCcon(ccon)
	defer C.gorods_free_string_result(&result)
	unsafeArr := unsafe.Pointer(result.strArr)
	arrLen := int(result.size)
	slice := (*[1 << 30]*C.char)(unsafeArr)[:arrLen:arrLen]
	if grps, err := usr.con.Groups(); err == nil {
		response := make(Groups, 0)
		for _, groupName := range slice {
			gName := C.GoString(groupName)
			if gName != usr.name {
				grp := grps.FindByName(gName, usr.con)
				if grp != nil {
					response = append(response, grp)
				} else {
					return nil, newError(Fatal, -1, fmt.Sprintf("iRODS FetchGroups Failed: Group in response not found in cache"))
				}
			}
		}
		return response, nil
	} else {
		return nil, err
	}
}
func (usr *User) FetchInfo() (map[string]string, error) {
	var (
		result C.goRodsStringResult_t
		err    *C.char
	)
	result.size = C.int(0)
	cUser := C.CString(usr.name)
	defer C.free(unsafe.Pointer(cUser))
	ccon := usr.con.GetCcon()
	if status := C.gorods_get_user(cUser, ccon, &result, &err); status != 0 {
		usr.con.ReturnCcon(ccon)
		return nil, newError(Fatal, status, fmt.Sprintf("iRODS Get Users Failed: %v", C.GoString(err)))
	}
	usr.con.ReturnCcon(ccon)
	defer C.gorods_free_string_result(&result)
	unsafeArr := unsafe.Pointer(result.strArr)
	arrLen := int(result.size)
	slice := (*[1 << 30]*C.char)(unsafeArr)[:arrLen:arrLen]
	response := make(map[string]string)
	for _, userInfo := range slice {
		userAttributes := strings.Split(strings.Trim(C.GoString(userInfo), " \n"), "\n")
		for _, attr := range userAttributes {
			split := strings.Split(attr, ": ")
			attrName := split[0]
			attrVal := split[1]
			response[attrName] = attrVal
		}
	}
	return response, nil
}
func (usr *User) AddToGroup(grp interface{}) error {
	switch grp.(type) {
	case string:
		return addToGroup(usr.name, usr.zone, grp.(string), usr.con)
	case *Group:
		return addToGroup(usr.name, usr.zone, (grp.(*Group)).name, usr.con)
	default:
	}
	return newError(Fatal, -1, fmt.Sprintf("iRODS AddToGroup Failed: unknown type passed"))
}
func (usr *User) RemoveFromGroup(grp interface{}) error {
	switch grp.(type) {
	case string:
		return removeFromGroup(usr.name, usr.zone, grp.(string), usr.con)
	case *Group:
		return removeFromGroup(usr.name, usr.zone, (grp.(*Group)).name, usr.con)
	default:
	}
	return newError(Fatal, -1, fmt.Sprintf("iRODS RemoveFromGroup Failed: unknown type passed"))
}
func (usr *User) ChangePassword(newPass string) error {
	var (
		err *C.char
	)
	cUserName := C.CString(usr.Name())
	cNewPass := C.CString(newPass)
	cMyPass := C.CString(usr.Con().Options.Password)
	defer C.free(unsafe.Pointer(cUserName))
	defer C.free(unsafe.Pointer(cNewPass))
	defer C.free(unsafe.Pointer(cMyPass))
	ccon := usr.Con().GetCcon()
	defer usr.Con().ReturnCcon(ccon)
	if status := C.gorods_change_user_password(cUserName, cNewPass, cMyPass, ccon, &err); status != 0 {
		return newError(Fatal, status, fmt.Sprintf("iRODS ChangePassword Failed: %v", C.GoString(err)))
	}
	return nil
}
func (usr *User) Attribute(attrName string) (Metas, error) {
	if meta, err := usr.Meta(); err == nil {
		return meta.Get(attrName)
	} else {
		return nil, err
	}
}
func (usr *User) AddMeta(m Meta) (nm *Meta, err error) {
	var mc *MetaCollection
	if mc, err = usr.Meta(); err != nil {
		return
	}
	nm, err = mc.Add(m)
	return
}