// NewUpdateTx is called on Channels which are in phase OPEN. It makes a new UpdateTx,
// signs it, saves it as MyProposedUpdateTx, and sends it to the Counterparty.
func (a *CallerAPI) NewUpdateTx(state []byte, channelID string, fast bool) error {
	var err error
	return a.DB.Update(func(tx *bolt.Tx) error {
		ch := &core.Channel{}
		ch, err = access.GetChannel(tx, channelID)
		if err != nil {
			return err
		}

		utx := ch.NewUpdateTx(state, fast)

		ev, err := core.SerializeUpdateTx(utx)
		if err != nil {
			return err
		}

		ch.SignProposedUpdateTx(ev, utx)

		err = a.CounterpartyClient.AddProposedUpdateTx(ev, ch.Counterparty.Address)
		if err != nil {
			return err
		}

		err = access.SetChannel(tx, ch)
		if err != nil {
			return err
		}

		return nil
	})
}
func (a *CallerAPI) CloseChannel(channelID string) error {
	return a.DB.View(func(tx *bolt.Tx) error {
		ch, err := access.GetChannel(tx, channelID)
		if err != nil {
			return err
		}

		if ch.LastFullUpdateTx != nil {
			err = a.JudgeClient.AddFullUpdateTx(ch.LastFullUpdateTxEnvelope, ch.Judge.Address)
			if err != nil {
				return err
			}
		}

		ev, err := core.SerializeClosingTx(ch.NewClosingTx())
		ch.Account.AppendSignature(ev)

		err = a.JudgeClient.AddClosingTx(ev, ch.Judge.Address)
		if err != nil {
			return err
		}

		return nil
	})
}
// This gets the channel from the judge and checks if it has changed, and does stuff if it has
func (a *CallerAPI) CheckChannel(chId string) error {
	return a.DB.Update(func(tx *bolt.Tx) error {
		ch, err := access.GetChannel(tx, chId)
		if err != nil {
			return err
		}

		b, err := a.JudgeClient.GetChannel(chId, ch.Judge.Address)
		if err != nil {
			return err
		}

		jch := &core.Channel{}
		json.Unmarshal(b, jch)

		// This means that the judge has signed the channel
		if ch.Phase == core.PENDING_OPEN && jch.Phase == core.OPEN {
			ch.Open(jch.OpeningTxEnvelope, jch.OpeningTx)
			if err != nil {
				return err
			}
		}

		err = access.SetChannel(tx, ch)
		if err != nil {
			return err
		}

		return nil
	})
}
func (a *CounterpartyAPI) AddFullUpdateTx(ev *wire.Envelope) error {
	return a.DB.Update(func(tx *bolt.Tx) error {
		utx := &wire.UpdateTx{}
		err := proto.Unmarshal(ev.Payload, utx)
		if err != nil {
			return err
		}
		ch, err := access.GetChannel(tx, utx.ChannelId)
		if err != nil {
			return err
		}

		err = ch.AddFullUpdateTx(ev, utx)
		if err != nil {
			return err
		}

		access.SetChannel(tx, ch)
		if err != nil {
			return errors.New("database error")
		}

		return nil
	})
}
func (a *CounterpartyAPI) AddChannel(ev *wire.Envelope) error {
	var err error

	otx := &wire.OpeningTx{}
	err = proto.Unmarshal(ev.Payload, otx)
	if err != nil {
		return err
	}

	acct := &core.Account{}
	cpt := &core.Counterparty{}
	err = a.DB.Update(func(tx *bolt.Tx) error {
		_, nilErr := access.GetChannel(tx, otx.ChannelId)
		if nilErr == nil {
			return errors.New("channel already exists")
		}
		_, ok := nilErr.(*access.NilError)
		if !ok {
			return err
		}

		cpt, err = access.GetCounterparty(tx, otx.Pubkeys[0])
		if err != nil {
			return err
		}

		acct, err = access.GetAccount(tx, otx.Pubkeys[1])
		if err != nil {
			return err
		}

		err = acct.CheckOpeningTx(ev, cpt)
		if err != nil {
			return err
		}

		ch, err := core.NewChannel(ev, otx, acct, cpt)
		if err != nil {
			return err
		}

		access.SetChannel(tx, ch)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return err
	}

	return nil
}
// CosignProposedUpdateTx cosigns the Channel's TheirProposedUpdateTx, saves it to
// LastFullUpdateTx, and sends it to the Counterparty.
func (a *CallerAPI) CosignProposedUpdateTx(channelID string) error {
	return a.DB.Update(func(tx *bolt.Tx) error {
		ch, err := access.GetChannel(tx, channelID)
		if err != nil {
			return err
		}

		ev := ch.CosignProposedUpdateTx()

		err = access.SetChannel(tx, ch)
		if err != nil {
			return err
		}

		err = a.CounterpartyClient.AddFullUpdateTx(ev, ch.Counterparty.Address)
		if err != nil {
			return err
		}

		return nil
	})
}
// AcceptChannel is called on Channels which are in phase PENDING_OPEN. It signs
// the Channel's OpeningTx and sends it to the Judge.
func (a *CallerAPI) AcceptChannel(channelID string) error {
	var err error
	return a.DB.Update(func(tx *bolt.Tx) error {
		var ch *core.Channel
		ch, err = access.GetChannel(tx, channelID)
		if err != nil {
			return err
		}

		ch.Account.AppendSignature(ch.OpeningTxEnvelope)

		err = access.SetChannel(tx, ch)
		if err != nil {
			return err
		}

		err = a.JudgeClient.AddChannel(ch.OpeningTxEnvelope, ch.Judge.Address)
		if err != nil {
			return err
		}

		return nil
	})
}