package state

import (
	"context"
	"sync"
	"sync/atomic"
)

type ObjectLock struct {
	lock     *sync.RWMutex
	condLock   *sync.Cond
	nWaitLock0 int32  //等待的协程数
	l          int32
}

func NewObjectLock(ctx context.Context) *ObjectLock {
	return &ObjectLock{
		lock: new(sync.RWMutex),
		condLock: sync.NewCond(new(sync.Mutex)),
	}
}

func (oLock *ObjectLock) RLock() {
	oLock.lock.RLock()
}

func (oLock *ObjectLock) RUnLock()  {
	oLock.lock.RUnlock()
}

func (oLock *ObjectLock) Lock0()  {
	atomic.AddInt32(&oLock.nWaitLock0,1)
	oLock.lock.Lock()
}

func (oLock *ObjectLock) UnLock0()  {
	oLock.lock.Unlock()
	if atomic.AddInt32(&oLock.nWaitLock0,-1) == 0 && atomic.CompareAndSwapInt32(&oLock.l,1,0) {
		oLock.condLock.Broadcast()
	}
}

func (oLock *ObjectLock) Lock() {
	oLock.condLock.L.Lock()
	for atomic.CompareAndSwapInt32(&oLock.l,0,1) || atomic.LoadInt32(&oLock.nWaitLock0) > 0{
		oLock.condLock.Wait()
	}
	oLock.condLock.L.Unlock()
	oLock.lock.Lock()
}

func (oLock *ObjectLock) Unlock() {
	oLock.lock.Unlock()
	atomic.CompareAndSwapInt32(&oLock.l,1,0)
	oLock.condLock.Broadcast()
}
