func (s *State) channel(name string) *Channel {
	return s.channels[strings.ToLower(irc.Nick(name))]
}
channel looks up a channel without locking.
package data
import (
	"errors"
	"strings"
	"sync"
	"github.com/aarondl/ultimateq/irc"
)
var (
	errNetInfoMissing = errors.New("data: NetworkInfo missing")
)
type Self struct {
	User
	ChannelModes
}
type State struct {
	selfUser  *User
	selfModes ChannelModes
	channels map[string]*Channel
	users    map[string]*User
	channelUsers map[string]map[string]channelUser
	userChannels map[string]map[string]userChannel
	kinds *modeKinds
	protect sync.RWMutex
}
func NewState(netInfo *irc.NetworkInfo) (*State, error) {
	state := &State{}
	if err := state.SetNetworkInfo(netInfo); err != nil {
		return nil, err
	}
	state.selfModes = NewChannelModes(&modeKinds{})
	state.channels = make(map[string]*Channel)
	state.users = make(map[string]*User)
	state.channelUsers = make(map[string]map[string]channelUser)
	state.userChannels = make(map[string]map[string]userChannel)
	return state, nil
}
func (s *State) SetNetworkInfo(ni *irc.NetworkInfo) error {
	s.protect.Lock()
	defer s.protect.Unlock()
	if ni == nil {
		return errNetInfoMissing
	}
	if s.kinds != nil {
		return s.kinds.update(ni.Prefix(), ni.Chanmodes())
	}
	kinds, err := newModeKinds(ni.Prefix(), ni.Chanmodes())
	if err != nil {
		return err
	}
	s.kinds = kinds
	return nil
}
func (s *State) Self() Self {
	return Self{*s.selfUser, s.selfModes.Clone()}
}
func (s *State) User(nickorhost string) (User, bool) {
	s.protect.RLock()
	defer s.protect.RUnlock()
	nick := strings.ToLower(irc.Nick(nickorhost))
	var user User
	u, ok := s.users[nick]
	if ok {
		user = *u
	}
	return user, ok
}
func (s *State) Channel(channel string) (Channel, bool) {
	s.protect.RLock()
	defer s.protect.RUnlock()
	var ch Channel
	c, ok := s.channels[strings.ToLower(channel)]
	if ok {
		ch = *c.Clone()
	}
	return ch, ok
}
func (s *State) UserModes(nickorhost, channel string) (UserModes, bool) {
	s.protect.RLock()
	defer s.protect.RUnlock()
	var modes UserModes
	if channelModes := s.userModes(nickorhost, channel); channelModes != nil {
		modes = *channelModes
		return modes, true
	}
	return modes, false
}
func (s *State) NUsers() int {
	s.protect.RLock()
	defer s.protect.RUnlock()
	return len(s.users)
}
func (s *State) NChannels() int {
	s.protect.RLock()
	defer s.protect.RUnlock()
	return len(s.channels)
}
func (s *State) NChannelsByUser(nickorhost string) (n int, ok bool) {
	s.protect.RLock()
	defer s.protect.RUnlock()
	var ucs map[string]userChannel
	nick := strings.ToLower(irc.Nick(nickorhost))
	if ucs, ok = s.userChannels[nick]; ok {
		n = len(ucs)
	}
	return n, ok
}
func (s *State) NUsersByChannel(channel string) (n int, ok bool) {
	s.protect.RLock()
	defer s.protect.RUnlock()
	var cus map[string]channelUser
	channel = strings.ToLower(channel)
	if cus, ok = s.channelUsers[channel]; ok {
		n = len(cus)
	}
	return n, ok
}
func (s *State) EachUser(fn func(User) bool) {
	s.protect.RLock()
	defer s.protect.RUnlock()
	for _, u := range s.users {
		if fn(*u) {
			break
		}
	}
}
func (s *State) EachChannel(fn func(Channel) bool) {
	s.protect.RLock()
	defer s.protect.RUnlock()
	for _, c := range s.channels {
		if fn(*c.Clone()) {
			break
		}
	}
}
func (s *State) Users() []string {
	s.protect.RLock()
	defer s.protect.RUnlock()
	ret := make([]string, 0, len(s.users))
	for _, u := range s.users {
		ret = append(ret, u.Host.String())
	}
	return ret
}
func (s *State) Channels() []string {
	s.protect.RLock()
	defer s.protect.RUnlock()
	ret := make([]string, 0, len(s.channels))
	for _, c := range s.channels {
		ret = append(ret, c.Name)
	}
	return ret
}
func (s *State) ChannelsByUser(nickorhost string) []string {
	s.protect.RLock()
	defer s.protect.RUnlock()
	nick := strings.ToLower(irc.Nick(nickorhost))
	if ucs, ok := s.userChannels[nick]; ok {
		ret := make([]string, 0, len(ucs))
		for _, uc := range ucs {
			ret = append(ret, uc.Channel.Name)
		}
		return ret
	}
	return nil
}
func (s *State) UsersByChannel(channel string) []string {
	s.protect.RLock()
	defer s.protect.RUnlock()
	channel = strings.ToLower(channel)
	if cus, ok := s.channelUsers[channel]; ok {
		ret := make([]string, 0, len(cus))
		for _, cu := range cus {
			ret = append(ret, cu.User.Host.String())
		}
		return ret
	}
	return nil
}
func (s *State) IsOn(nickorhost, channel string) bool {
	s.protect.RLock()
	defer s.protect.RUnlock()
	nick := strings.ToLower(irc.Nick(nickorhost))
	channel = strings.ToLower(channel)
	if chans, ok := s.userChannels[nick]; ok {
		_, ok = chans[channel]
		return ok
	}
	return false
}
func (s *State) user(nickorhost string) *User {
	return s.users[strings.ToLower(irc.Nick(nickorhost))]
}