;;; ---------------------------------------------------------------------------
;;; Contract: Arithmetic
;;;
;;; Copyright 2016 Daniel Ellison
;;;
;;;    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.
;;;
;;; Version:
;;; 0.0.1

;; ----------------------------------------------------------------------------
;; Start of Arithmetic.

(seq

  ;; --------------------------------------------------------------------------
  ;; INIT

  ;; Include standard libraries.
  (include "../lib/constants.lll")
  (include "../lib/utilities.lll")

  ;; --------------------------------------------------------------------------
  ;; CODE

  (returnlll
    (seq contract-enabled

      ;; ----------------------------------------------------------------------
      ;; Initialize the contract function return sizes. We don't include
      ;; initialize() itself as it's called directly from either the dispatcher
      ;; or a contract that's replacing itself with another.
      ;;
      ;; Signature: initialize()
      ;; Returns: true

      (when (= function-id initialize)
        (seq only-owner

          ;; Set up function return sizes for this contract. Adding the
          ;; contract address and the function hash together makes each
          ;; function return size unique to this contract.
          (sstore (+ @@contract-address replace) 32)
          (sstore (+ @@contract-address double) 32)
          (sstore (+ @@contract-address halve) 32)

          ;; Log success and return true.
          (mstore call-result true)
          (log1 call-result 32 (sha3 0x00 (lit 0x00 "Initialized(bool)")))
          (stop)))

      ;; ----------------------------------------------------------------------
      ;; Replace this contract with the contract at the address provided.
      ;;
      ;; Signature: replace(address)
      ;; Returns: address of new contract

      (when (= function-id replace)
        (seq only-owner no-contract-address

          ;; Disable this contract.
          (sstore @@contract-address false)

          ;; Save old and new contract addresses to memory for logging.
          (mstore old-address @@contract-address)
          (mstore new-address (calldataload 4))

          ;; Set new contract address and enable it.
          (sstore contract-address @new-address)
          (sstore @@contract-address true)

          ;; Call the new contract's initialize() function.
          (mstore call-data (pad-right initialize))
          (delegatecall (- (gas) 1000) @@contract-address
              call-data 32 return-data 0)

          ;; Log and return result.
          (log2 new-address 32
              (sha3 0x00 (lit 0x00 "Replaced(address,address)"))
              @old-address)
          (return @@contract-address)))

      ;; ----------------------------------------------------------------------
      ;; This multiplies the supplied number by 2.
      ;;
      ;; Signature: double(uint256)
      ;; Returns: product of multiplication

      (when (= function-id double)
        (seq

          ;; Do the doubling and save the result.
          (mstore call-result (mul (calldataload 4) 2))

          ;; Log and return result.
          (log1 call-result 32 (sha3 0x00 (lit 0x00 "Doubled(uint256)")))
          (return call-result 32)))

      ;; ----------------------------------------------------------------------
      ;; This divides the supplied number by 2.
      ;;
      ;; Signature: halve(uint256)
      ;; Returns: quotient of division

      (when (= function-id halve)
        (seq

          ;; Do the halving and save the result.
          (mstore call-result (div (calldataload 4) 2))

          ;; Log and return result.
          (log1 call-result 32 (sha3 0x00 (lit 0x00 "Halved(uint256)")))
          (return call-result 32)))

      ;; ----------------------------------------------------------------------
      ;; Fallback: No functions matched the function ID provided so we jump to
      ;; an invalid location which causes an exception in the EVM. This results
      ;; in any ether sent to the contract to be returned to the caller.

      (jump invalid-location)))

;; ----------------------------------------------------------------------------
;; End of Arithmetic.

)
