/*
==================================================================================
  Copyright (c) 2019 AT&T Intellectual Property.
  Copyright (c) 2019 Nokia

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
==================================================================================
*/

package control

import (
	"fmt"
	"gerrit.o-ran-sc.org/r/ric-plt/xapp-frame/pkg/xapp"
	"sync"
)

//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
type Tracker struct {
	mutex                sync.Mutex
	transactionXappTable map[TransactionXappKey]*TransactionXapp
	transSeq             uint64
}

func (t *Tracker) Init() {
	t.transactionXappTable = make(map[TransactionXappKey]*TransactionXapp)
}

func (t *Tracker) initTransaction(transBase *Transaction) {
	t.mutex.Lock()
	defer t.mutex.Unlock()
	transBase.EventChan = make(chan interface{})
	transBase.tracker = t
	transBase.Seq = t.transSeq
	t.transSeq++
}

func (t *Tracker) NewSubsTransaction(subs *Subscription) *TransactionSubs {
	trans := &TransactionSubs{}
	trans.Meid = subs.GetMeid()
	t.initTransaction(&trans.Transaction)
	xapp.Logger.Debug("CREATE %s", trans.String())
	return trans
}

func (t *Tracker) NewXappTransaction(
	endpoint *RmrEndpoint,
	xid string,
	subid uint32,
	meid *xapp.RMRMeid) *TransactionXapp {

	trans := &TransactionXapp{}
	trans.XappKey = &TransactionXappKey{*endpoint, xid}
	trans.Meid = meid
	trans.SubId = subid
	t.initTransaction(&trans.Transaction)
	xapp.Logger.Debug("CREATE %s", trans.String())
	return trans
}

func (t *Tracker) Track(trans *TransactionXapp) error {

	if trans.GetEndpoint() == nil {
		err := fmt.Errorf("Tracker: No valid endpoint given in %s", trans.String())
		return err
	}

	t.mutex.Lock()
	defer t.mutex.Unlock()

	theKey := *trans.XappKey

	if othtrans, ok := t.transactionXappTable[theKey]; ok {
		err := fmt.Errorf("Tracker: %s is ongoing, not tracking %s", othtrans, trans)
		return err
	}

	trans.tracker = t
	t.transactionXappTable[theKey] = trans
	xapp.Logger.Debug("Tracker: Append %s", trans.String())
	//xapp.Logger.Debug("Tracker: transtable=%v", t.transactionXappTable)
	return nil
}

func (t *Tracker) UnTrackTransaction(xappKey TransactionXappKey) (*TransactionXapp, error) {
	t.mutex.Lock()
	defer t.mutex.Unlock()
	if trans, ok2 := t.transactionXappTable[xappKey]; ok2 {
		xapp.Logger.Debug("Tracker: Remove %s", trans.String())
		delete(t.transactionXappTable, xappKey)
		//xapp.Logger.Debug("Tracker: transtable=%v", t.transactionXappTable)
		return trans, nil
	}
	return nil, fmt.Errorf("Tracker: No record %s", xappKey)
}
