text:
!------------------------------------------------------------------------------
! IMPT, ProjectFortran
!------------------------------------------------------------------------------
!
! MODULE: Module class_io
!
!> @author
!> Module Author Ilkay Solak
!
! DESCRIPTION:
!>  Input/Output module, by using netcdf files. Brief description of module.
!
! REVISION HISTORY:
! 01/07/2007 - Initial Version by Matthieu Marquillie
! 13/11/2016 - Updated Version by Ilkay Solak
!
! @todo Whole class only works for ndim = 3 in the current version
! @todo Needs to be tested, waiting for CMakeList.txt update
!------------------------------------------------------------------------------

module class_io
  use netcdf
  use precision
  use class_field
!  use class_mpi    ! not planned yet
  implicit none

  !-> Declare everything private by default
  private

  !-> Declare exported procedure
  public :: write_var3d, read_var3d
  public :: get_dim_size
  public :: get_var3d_info

contains

  !---------------------------------------------------------------------------
  !> @author
  !> Routine Author Matthieu Marquillie
  !
  ! DESCRIPTION:
  !> Write 3d variable in a netcdf file
  !> @brief
  !> Write 3d variable in a netcdf file
  !
  ! REVISION HISTORY:
  ! 01/07/2011 - Initial Version by Matthieu Marquillie
  ! 13/11/2016 - Updated Version by Ilkay Solak
  !
  !> @param[in] file_name       - name of the file
  !> @param[in] dim_name(ndim)  - name of the dimensions
  !> @param[in] dim_len(ndim)   - length of the dimensions
  !> @param[in] var_name        - name of the variable
  !> @param[in] var             - variable to save
  !> @param[in] istart(ndim)    - start points, per process if MPI
  !> @param[in] icount(ndim)    - end points, per process if MPI

  !> @param[out] N/A
  !> @return N/A
  !---------------------------------------------------------------------------

  subroutine write_var3d(file_name,dim_name,dim_len,&
                         var_name,var,istart,icount)
    implicit none
    integer(ik),parameter :: ndim=3
    character(len=*),intent(in) :: file_name, dim_name(ndim)
    character(len=*),intent(in) :: dim_len(ndim), var_name
    real(rk),intent(in) :: var(:,:,:)
    integer(ik),intent(in) :: istart(3),icount(3)

    logical :: file_exist
    integer(ik) :: varid(1),i
    integer(ik) :: ncid,dimid(ndim),
    integer(ik) :: dim_len_check,dim_var(ndim),imap(3)

    !-> check if file exist
    inquire(file=file_name,exist=file_exist)

    !-> open/create file
    if (file_exist) then
      call io_check(nf90_open(path=file_name,mode=nf90_write,ncid=ncid))
      call io_check(nf90_redef(ncid))
    else
      call io_check(nf90_create(path=file_name,cmode=nf90_clobber,ncid=ncid))
    endif

    !-> create/add dimensions
    do i=1,ndim
       if (nf90_inq_dimid(ncid,dim_name(i),dimid(i))/=nf90_noerr) then
          call io_check(nf90_def_dim(ncid,dim_name(i),dim_len(i),dimid(i)))
       else
          call io_check(nf90_inquire_dimension(ncid,dimid(i),len=dim_len_check))
          if (dim_len_check/=dim_len(i)) call error_stop("NETCDF Error : wrong dimensions")
       endif
    enddo

    !-> if variable exist         : get variable id
    !-> if variable doesn't exist : define variable
    if (nf90_inq_varid(ncid,var_name,varid(1))/=nf90_noerr) then
       call io_check(nf90_def_var(ncid,var_name,nf90_real,dimid,varid(1)))
    endif

    !-> end of definition
    call io_check(nf90_enddef(ncid))

    dim_var=get_dim_size(var)

    imap(1)=1
    imap(2)=dim_var(1)*imap(1)
    imap(3)=dim_var(2)*imap(2)

    !-> write field variable
    call io_check(nf90_put_var(ncid,varid(1),var,start=istart,count=icount,map=imap))

    !-> close file
    call io_check(nf90_close(ncid))

  end subroutine write_var3d

  !---------------------------------------------------------------------------
  !> @author
  !> Routine Author Matthieu Marquillie
  !
  ! DESCRIPTION:
  !> Read 3d variable from a netcdf file
  !> @brief
  !> Read 3d variable from a netcdf file
  !
  ! REVISION HISTORY:
  ! 01/07/2011 - Initial Version by Matthieu Marquillie
  ! 13/11/2016 - Updated Version by Ilkay Solak
  !
  !> @param[in] file_name       - name of the file
  !> @param[in] var_name        - name of the variable
  !> @param[in] istart(ndim)    - start points, per process if MPI
  !> @param[in] icount(ndim)    - end points, per process if MPI

  !> @param[inout] var          - variable to read
  !> @return var(:,:,:) real(rk)
  !---------------------------------------------------------------------------
  subroutine read_var3d(file_name,var_name,var,istart,icount)
    implicit none
    character(len=*),intent(in) :: file_name,var_name
    real(rk) :: var(:,:,:)
    integer(ik),intent(in) :: istart(3),icount(3)

    integer(ik) :: varid(1),i,ncid

    !-> open file
    call io_check(nf90_open(path=file_name,mode=nf90_nowrite,ncid=ncid))

    !-> get var id
    call io_check(nf90_inq_varid(ncid,var_name,varid(1)))

    !-> get var
    call io_check(nf90_get_var(ncid,varid(1),var,start=istart,count=icount))

    !-> close file
    call io_check(nf90_close(ncid))

  end subroutine read_var3d

  !---------------------------------------------------------------------------
  !> @author
  !> Routine Author Matthieu Marquillie
  !
  ! DESCRIPTION:
  !> Get 3d variable dimension length in a netcdf file
  !> @brief
  !> Get 3d variable dimension length in a netcdf file
  !
  ! REVISION HISTORY:
  ! 01/07/2011 - Initial Version by Matthieu Marquillie
  ! 13/11/2016 - Updated Version by Ilkay Solak
  !
  !> @param[in] file_name          - name of the file
  !> @param[in] var_name           - name of the variable
  !> @param[inout] dim_name(ndim)  - name of the dimensions
  !> @param[inout] dim_len(ndim)   - length of the dimensions

  !> @return dim_name(ndim), dim_len(ndim) character(len=*)
  !---------------------------------------------------------------------------
  subroutine get_var3d_info(file_name,var_name,dim_name,dim_len)
    implicit none
    integer(ik),parameter :: ndim=3
    character(len=*),intent(in) :: file_name,var_name
    character(len=*),intent(inout) :: dim_name(ndim), dim_len(ndim)

    integer(ik) :: varid(1)
    integer(ik) :: i,ncid,dimid(ndim)

    !-> open file
    call io_check(nf90_open(path=file_name,mode=nf90_nowrite,ncid=ncid))

    !-> get variable id
    call io_check(nf90_inq_varid(ncid,var_name,varid(1)))

    !-> get variable dimensions id
    call io_check(nf90_inquire_variable(ncid,varid(1),dimids=dimid))

    !-> get dimensions length
    do i=1,ndim
       call io_check(nf90_inquire_dimension(ncid,dimid(i),name=dim_name(i),len=dim_len(i)))
    enddo

    !-> close file
    call io_check(nf90_close(ncid))

  end subroutine get_var3d_info

  !---------------------------------------------------------------------------
  !> @author
  !> Routine Author Matthieu Marquillie
  !
  ! DESCRIPTION:
  !> Returns the size of each dimension for 3d field
  !> @brief
  !> Returns the size of each dimension for 3d field
  !
  ! REVISION HISTORY:
  ! 01/06/2011 - Initial Version by Matthieu Marquillie
  ! 13/11/2016 - Updated Version by Ilkay Solak
  !
  !> @param[in] x          - name of the file
  !> @param[in] var_name           - name of the variable
  !> @param[inout] dim_name(ndim)  - name of the dimensions
  !> @param[inout] dim_len(ndim)   - length of the dimensions

  !> @todo Should be only in class_field, not here
  !---------------------------------------------------------------------------
  function get_dim_size(x)
    implicit none
    integer :: get_dim_size(3)
    real(rk),intent(in) :: x(:,:,:)
    integer(ik) :: i
    do i=1,3
       get_dim_size(i)=size(x,dim=i)
    enddo

  end function get_dim_size

  !---------------------------------------------------------------------------
  !> @author
  !> Routine Author Matthieu Marquillie
  !
  ! DESCRIPTION:
  !> Check netcdf error output and stop code if needed
  !> @brief
  !> Check netcdf error output and stop code if needed
  !
  ! REVISION HISTORY:
  ! 01/06/2011 - Initial Version by Matthieu Marquillie
  ! 13/11/2016 - Updated Version by Ilkay Solak
  !
  !> @param[in] status          - error status for netcdf
  !---------------------------------------------------------------------------
  subroutine io_check(status)
    implicit none
    integer,intent(in) :: status

    if(status /= nf90_noerr) then
       print*,trim(nf90_strerror(status))
       print'(a)',"Netcdf Error : aborting"
       stop
    end if

  end subroutine io_check

end module class_io


text:
import imp,time,sys,os,EmulationManager
import datetime as dt
import sqlite3 as sqlite
import logging
import EMQproducer, Library
from EMQproducer import Producer
from Distribution import distribution
from Logger import singleLogger

import Pyro4
Pyro4.config.HMAC_KEY='pRivAt3Key'
#Pyro4.config.SERIALIZER='pickle'
#perhaps needs to be set somewhere else

distLoggerDM=None

global producer
producer = Producer()
# EMQproducer.StreamAndBroadcastHandler("Distribution Manager",producer,logging.INFO)

global HOMEPATH
HOMEPATH = Library.getHomepath()

def createDistribution(newEmulation):
    daemon=Library.getDaemon()

    global producer
    if producer is None:
        # print "In distributionManager, copying producer"
        producer = producer()

    # print "Who calls "+sys._getframe(0).f_code.co_name+": "+sys._getframe(1).f_code.co_name
#    distLoggerDM = ""

    # if distLoggerDM is None:
    #        distLoggerDM=Library.loggerSet("Distribution Manager",str(newEmulation.emulationID)+"-"+str(newEmulation.emulationName)+"-syslog"+"_"+str(newEmulation.startTimeEmu)+".csv")

    # connecting to the DB and storing parameters
    loggerJobReply = "No logger scheduled"
    try:

        conn = Library.dbconn()
        c = conn.cursor()

        # 1. Populate "emulation"
        c.execute('INSERT INTO emulation (emulationName,emulationType,resourceType,active,logging,logFrequency,logLevel,xmlData) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [newEmulation.emulationName, newEmulation.emulationType, newEmulation.resourceTypeEmulation, 1, newEmulation.emulationLog, newEmulation.emulationLogFrequency, newEmulation.emulationLogLevel, newEmulation.xmlData])
        newEmulation.setEmulationID(c.lastrowid)
        # start logger here once we know emulation ID
#        distLoggerDM = singleLogger("Distribution Manager", None, str(newEmulation.emulationID) + "-" + str(newEmulation.emulationName) + "-syslog" + "_" + str(newEmulation.startTimeEmu) + ".csv")

        c.execute('UPDATE emulation SET emulationName=? WHERE emulationID =?', (str(newEmulation.emulationID) + "-" + newEmulation.emulationName, newEmulation.emulationID))

        # 2. We populate "emulationLifetime" table
        c.execute('INSERT INTO emulationLifetime (startTime,stopTime,emulationID) VALUES (?,?,?)', [newEmulation.startTimeEmu, newEmulation.stopTimeEmu, newEmulation.emulationID])
        emulationLifetimeID = c.lastrowid

        newEmulation.setEmulationLifetimeID(emulationLifetimeID)
        c.execute('UPDATE emulationLifetime SET stopTime=? WHERE emulationLifetimeID =?',(newEmulation.stopTimeEmu,emulationLifetimeID))
        c.execute('UPDATE emulation SET emulationLifetimeID=? WHERE emulationID=?',(emulationLifetimeID,newEmulation.emulationID))

        conn.commit()
        c.close()

        """
        # Here we create runs
        """

#        raise Exception ("newEmulation.emulationLog = " + str(newEmulation.emulationLog))
        if newEmulation.emulationLog == "1":

            # creating run for logger with probe interval of 2 seconds
            distLoggerDM = singleLogger("Distribution Manager", None, str(newEmulation.emulationID) + "-" + str(newEmulation.emulationName) + "-syslog" + "_" + str(newEmulation.startTimeEmu) + ".csv")
            interval = int(newEmulation.emulationLogFrequency)
            singleRunStartTime = Library.timeConv(newEmulation.startTimeEmu)
            loggerJobReply = daemon.createLoggerJob(singleRunStartTime, newEmulation.stopTimeEmu, interval, newEmulation.emulationID, newEmulation.emulationName, newEmulation.startTimeEmu)

        createEndJob(daemon, newEmulation)

    except sqlite.Error, e:
        print e
        return "SQL error:", e
        sys.exit(1)

    createDistributionRuns(newEmulation)

def createEndJob (daemon, newEmulation):
    returnEmulationName = (str(newEmulation.emulationID) + "-" + newEmulation.emulationName)
    #Calcualte when the end job should be (start + duration +1) //+1 is to allow for delay in scheduler starting emulation
    emulationEndTime = (Library.timeConv(newEmulation.startTimeEmu)) + dt.timedelta(0, (float(newEmulation.stopTimeEmu) + 1))
    emulationEndJobReply = daemon.createEmulationEndJob(emulationEndTime, returnEmulationName)

def createDistributionRuns(newEmulation):
    daemon=Library.getDaemon()
    daemon.setEmuObject(newEmulation)

    for distro in newEmulation.distroList:

        if distro.getDistributionID() != "none":
            #do nothing continue to next element, because this distribution was already scheduled.
            print "Already scheduled"

        else:

            try:
                conn = Library.dbconn()
                c = conn.cursor()

                # 1. We populate "distribution" table
                c.execute('INSERT INTO distribution (distributionGranularity, distributionType,emulator,distributionName,startTime,duration,emulationID) VALUES (?, ?, ?, ?,?, ?,?)', [distro.granularity, distro.type, distro.emulatorName,distro.name,distro.startTime,distro.duration,newEmulation.emulationID])
                distro.setDistributionID(c.lastrowid)
                daemon.setEmuObject(newEmulation)
                '''
                {'startLoad': u'10', 'stopLoad': u'90'}
                '''
                #print "distributionArg:", distributionArg
                #print "emulatorArg:",emulatorArg

                #2. populate DistributionParameters, of table determined by distributionType name in our test it is "linearDistributionParameters"
                for d in distro.distroArgs :
                    c.execute('INSERT INTO DistributionParameters (paramName,value,distributionID) VALUES (?, ?, ?)',[d,distro.distroArgs[d],distro.ID])
                distributionParametersID=c.lastrowid

                c.execute('UPDATE distribution SET distributionParametersID=? WHERE distributionID =?',(distributionParametersID,distro.ID))

                for emu in distro.emulatorArg :
                    c.execute('INSERT INTO EmulatorParameters (paramName,value,resourceType,distributionID) VALUES (?, ?, ?,?)',[emu,distro.emulatorArg[emu],distro.resourceType,distro.ID])
                distributionParametersID=c.lastrowid

                conn.commit()
                c.close()
            except sqlite.Error, e:
                print "Error %s:" % e.args[0]
                print e
                sys.exit(1)

            startTime= Library.timeConv(newEmulation.startTimeEmu)
            startTimesec=time.mktime(startTime.timetuple()) + float(distro.startTime)
            #making sure that the run after event has valid date for scheduling
            nowTime = Library.timeSinceEpoch(5)
            if startTimesec < nowTime:
                startTimesec = nowTime + float(distro.startTime)

            '''
            1. Load the module according to Distribution Type to create runs
            '''

            #1. Get required module loaded
            modhandleMy=Library.loadDistribution(distro.type)
            #Check if error returned
            if (type(modhandleMy) is str):
                raise Exception (modhandleMy)

            #2. Use this module for calculation and run creation
            stressValues,runStartTime,runDurations,triggerType=modhandleMy(newEmulation.emulationID,newEmulation.emulationName,newEmulation.getEmulationLifetimeID(),startTimesec,distro.duration, int(distro.granularity),distro.distroArgs,distro.resourceType,HOMEPATH)

            if (distro.type != "event"): #event distributions don't require a minjobtime
                try:
                    if (distro.distroArgs.has_key("minjobtime")):
                        minJobTime = distro.distroArgs["minjobtime"]
                    else:
                        minJobTime = 2
                    (stressValues, runStartTime, runDurations) = Library.checkMinJobTime(distro.name, stressValues, runStartTime, runDurations, distro.distroArgs["minjobtime"])
                except Exception, e:
                    print "Could not enforce minimum job time. " + str(e)

            runStartTime = Library.staggerStartTimes(runStartTime)
            (stressValues, runStartTime, runDurations) = Library.removeZeroJobs(stressValues, runStartTime, runDurations) #Remove jobs with a stressValue of 0
            #event and time type disro's separation
            try :
                    n=0
                    for vals in stressValues:
                        #print "stressValues: ",vals
                        try:
                            #print "Things that are sent to daemon:\n",emulationID,emulationName,distributionName,emulationLifetimeID,runDurations[n],emulator,emulatorArg,resourceTypeDist,vals,runStartTime[n],str(n)
                            daemon.hello()
                            #Sending emulation name already including ID stamp
                            emulationNameID =str(newEmulation.emulationID)+"-"+str(newEmulation.emulationName)

                            schedulerReply = str(daemon.createJob(newEmulation.emulationID,emulationNameID,distro.ID,distro.name,newEmulation.getEmulationLifetimeID(),runDurations[n],distro.emulatorName,distro.emulatorArg,distro.resourceType,vals,runStartTime[n],str(n),runDurations[n]))
                            distLoggerDM=singleLogger("Distribution Manager",None,str(newEmulation.emulationID)+"-"+str(newEmulation.emulationName)+"-syslog"+"_"+str(newEmulation.startTimeEmu)+".csv")
                            distLoggerDM.info("Job Created: "+schedulerReply)

                            #adding values to the table for recovery
                            try:
                                conn = Library.dbconn()
                                c = conn.cursor()

                                # 1. We populate "distribution" table :stressValue,runStartTime,runNo
                                c.execute('INSERT INTO runLog (executed, stressValue, runStartTime,runNo,distributionID, runDuration) VALUES (?, ?, ?, ?, ?,?)', ["Pending", vals, runStartTime[n],str(n),distro.ID,runDurations[n]])

                                conn.commit()
                                c.close()
                            except sqlite.Error, e:
                                print "Error %s:" % e.args[0]
                                print e
                                sys.exit(1)

                            n= n+1

                        except  Pyro4.errors.CommunicationError, e:
                            print e
                            print "\n---Check if SchedulerDaemon is started. Connection error cannot create jobs---"

                    if triggerType=="time":
                        #schedule the next distro right after this will end
                        pass#maybe break
                    else:
                        raise Exception("Found trigger type '%s' in distribution '%s'.Stopping job scheduling" % (triggerType,distro.name))

            except Exception, e:
                #send copy of emulation object to daemon
                print "set emu exception:",e
                daemon.setEmuObject(newEmulation)
                break
                #"do something with remaining distributions to transfer them to the end of event driven distro"

if __name__ == "__main__":

    pass

redpajama_set_name: RedPajamaGithub


text:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Reactive;

namespace PhoneDragDrop
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            MouseEventHandler();
        }

        private void MouseEventHandler()
        {
            var mouseDown = from evt in Observable.FromEvent<MouseButtonEventArgs>(image, "MouseLeftButtonDown")
                            select evt.EventArgs.GetPosition(image);
            var mouseUp = Observable.FromEvent<MouseButtonEventArgs>(this, "MouseLeftButtonUp");
            var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>(this, "MouseMove")
                            select evt.EventArgs.GetPosition(this);

            var q = from startLocation in mouseDown
                    from endLocation in mouseMove.TakeUntil(mouseUp)
                    select new {
                        X = endLocation.X - startLocation.X,
                        Y = endLocation.Y - startLocation.Y
                    };

            q.Subscribe(value =>
            {
                Canvas.SetLeft(image, value.X);
                Canvas.SetTop(image, value.Y);
            });
        }
    }
}


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<title>Uses of Class physicalSystems.Wings</title>
<meta name="date" content="2015-11-14">
<link rel="stylesheet" type="text/css" href="../../stylesheet.css" title="Style">

JavaScript is disabled on your browser.

Skip navigation links

Overview

Package

Class

Use

Tree

Deprecated

Index

Help

Prev

Next

Frames

No Frames

All Classes

Uses of Class
physicalSystems.Wings

Packages that use Wings

Package
Description

physicalSystems

Uses of Wings in physicalSystems

Constructors in physicalSystems with parameters of type Wings

Constructor and Description

Airplane(Engine[] engines,
        Wings wings,
        Gyrocompass gyrocompass,
        GPS gps,
        double minClimbSpeed,
        int cruisingAltitude,
        double samplingTime)

Skip navigation links

Overview

Package

Class

Use

Tree

Deprecated

Index

Help

Prev

Next

Frames

No Frames

All Classes


text:
package org.killbill.billing.jaxrs.resources;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.PropertyResourceBundle;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicReference;

import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriInfo;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.ObjectType;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountUserApi;
import org.killbill.billing.catalog.DefaultPlanPhasePriceOverride;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.catalog.api.BillingPeriod;
import org.killbill.billing.catalog.api.Currency;
import org.killbill.billing.catalog.api.PhaseType;
import org.killbill.billing.catalog.api.PlanPhasePriceOverride;
import org.killbill.billing.catalog.api.PlanPhaseSpecifier;
import org.killbill.billing.catalog.api.ProductCategory;
import org.killbill.billing.entitlement.api.SubscriptionApiException;
import org.killbill.billing.entitlement.api.SubscriptionEventType;
import org.killbill.billing.invoice.api.DryRunArguments;
import org.killbill.billing.invoice.api.DryRunType;
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceApiException;
import org.killbill.billing.invoice.api.InvoiceItem;
import org.killbill.billing.invoice.api.InvoiceNotifier;
import org.killbill.billing.invoice.api.InvoicePayment;
import org.killbill.billing.invoice.api.InvoiceUserApi;
import org.killbill.billing.jaxrs.json.CustomFieldJson;
import org.killbill.billing.jaxrs.json.InvoiceDryRunJson;
import org.killbill.billing.jaxrs.json.InvoiceItemJson;
import org.killbill.billing.jaxrs.json.InvoiceJson;
import org.killbill.billing.jaxrs.json.InvoicePaymentJson;
import org.killbill.billing.jaxrs.json.PhasePriceOverrideJson;
import org.killbill.billing.jaxrs.json.TagJson;
import org.killbill.billing.jaxrs.util.Context;
import org.killbill.billing.jaxrs.util.JaxrsUriBuilder;
import org.killbill.billing.payment.api.Payment;
import org.killbill.billing.payment.api.PaymentApi;
import org.killbill.billing.payment.api.PaymentApiException;
import org.killbill.billing.payment.api.PluginProperty;
import org.killbill.billing.tenant.api.TenantApiException;
import org.killbill.billing.tenant.api.TenantKV.TenantKey;
import org.killbill.billing.tenant.api.TenantUserApi;
import org.killbill.billing.util.LocaleUtils;
import org.killbill.billing.util.api.AuditUserApi;
import org.killbill.billing.util.api.CustomFieldApiException;
import org.killbill.billing.util.api.CustomFieldUserApi;
import org.killbill.billing.util.api.TagApiException;
import org.killbill.billing.util.api.TagDefinitionApiException;
import org.killbill.billing.util.api.TagUserApi;
import org.killbill.billing.util.audit.AccountAuditLogs;
import org.killbill.billing.util.callcontext.CallContext;
import org.killbill.billing.util.callcontext.TenantContext;
import org.killbill.billing.util.entity.Pagination;
import org.killbill.clock.Clock;
import org.killbill.clock.ClockUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.codahale.metrics.annotation.Timed;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.inject.Inject;
import com.wordnik.swagger.annotations.Api;
import com.wordnik.swagger.annotations.ApiOperation;
import com.wordnik.swagger.annotations.ApiResponse;
import com.wordnik.swagger.annotations.ApiResponses;

import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static javax.ws.rs.core.MediaType.TEXT_HTML;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;

@Path(JaxrsResource.INVOICES_PATH)
@Api(value = JaxrsResource.INVOICES_PATH, description = "Operations on invoices")
public class InvoiceResource extends JaxRsResourceBase {

    private static final Logger log = LoggerFactory.getLogger(InvoiceResource.class);
    private static final String ID_PARAM_NAME = "invoiceId";
    private static final String LOCALE_PARAM_NAME = "locale";

    private final InvoiceUserApi invoiceApi;
    private final InvoiceNotifier invoiceNotifier;
    private final TenantUserApi tenantApi;
    private final Locale defaultLocale;

    private static final Ordering<InvoicePaymentJson> INVOICE_PAYMENT_ORDERING = Ordering.from(new Comparator<InvoicePaymentJson>() {
        @Override
        public int compare(final InvoicePaymentJson o1, final InvoicePaymentJson o2) {
            return o1.getTransactions().get(0).getEffectiveDate().compareTo(o2.getTransactions().get(0).getEffectiveDate());
        }
    });

    @Inject
    public InvoiceResource(final AccountUserApi accountUserApi,
                           final InvoiceUserApi invoiceApi,
                           final PaymentApi paymentApi,
                           final InvoiceNotifier invoiceNotifier,
                           final Clock clock,
                           final JaxrsUriBuilder uriBuilder,
                           final TagUserApi tagUserApi,
                           final CustomFieldUserApi customFieldUserApi,
                           final AuditUserApi auditUserApi,
                           final TenantUserApi tenantApi,
                           final Context context) {
        super(uriBuilder, tagUserApi, customFieldUserApi, auditUserApi, accountUserApi, paymentApi, clock, context);
        this.invoiceApi = invoiceApi;
        this.invoiceNotifier = invoiceNotifier;
        this.tenantApi = tenantApi;
        this.defaultLocale = Locale.getDefault();
    }

    @Timed
    @GET
    @Path("/{invoiceId:" + UUID_PATTERN + "}/")
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Retrieve an invoice by id", response = InvoiceJson.class)
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                           @ApiResponse(code = 404, message = "Invoice not found")})
    public Response getInvoice(@PathParam("invoiceId") final String invoiceId,
                               @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
                               @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                               @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException {
        final TenantContext tenantContext = context.createContext(request);
        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), tenantContext);
        final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(invoice.getAccountId(), auditMode.getLevel(), tenantContext);

        if (invoice == null) {
            throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceId);
        } else {
            final InvoiceJson json = new InvoiceJson(invoice, withItems, accountAuditLogs);
            return Response.status(Status.OK).entity(json).build();
        }
    }

    @Timed
    @GET
    @Path("/{invoiceNumber:" + NUMBER_PATTERN + "}/")
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Retrieve an invoice by number", response = InvoiceJson.class)
    @ApiResponses(value = {@ApiResponse(code = 404, message = "Invoice not found")})
    public Response getInvoiceByNumber(@PathParam("invoiceNumber") final Integer invoiceNumber,
                                       @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final boolean withItems,
                                       @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException {
        final TenantContext tenantContext = context.createContext(request);
        final Invoice invoice = invoiceApi.getInvoiceByNumber(invoiceNumber, tenantContext);
        final AccountAuditLogs accountAuditLogs = auditUserApi.getAccountAuditLogs(invoice.getAccountId(), auditMode.getLevel(), tenantContext);

        if (invoice == null) {
            throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceNumber);
        } else {
            final InvoiceJson json = new InvoiceJson(invoice, withItems, accountAuditLogs);
            return Response.status(Status.OK).entity(json).build();
        }
    }

    @Timed
    @GET
    @Path("/{invoiceId:" + UUID_PATTERN + "}/html")
    @Produces(TEXT_HTML)
    @ApiOperation(value = "Render an invoice as HTML", response = String.class)
    @ApiResponses(value = {@ApiResponse(code = 404, message = "Invoice not found")})
    public Response getInvoiceAsHTML(@PathParam("invoiceId") final String invoiceId,
                                     @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, IOException, AccountApiException {
        return Response.status(Status.OK).entity(invoiceApi.getInvoiceAsHTML(UUID.fromString(invoiceId), context.createContext(request))).build();
    }

    @Timed
    @GET
    @Path("/" + PAGINATION)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "List invoices", response = InvoiceJson.class, responseContainer = "List")
    @ApiResponses(value = {})
    public Response getInvoices(@QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset,
                                @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit,
                                @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final Boolean withItems,
                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException {
        final TenantContext tenantContext = context.createContext(request);
        final Pagination<Invoice> invoices = invoiceApi.getInvoices(offset, limit, tenantContext);
        final URI nextPageUri = uriBuilder.nextPage(InvoiceResource.class, "getInvoices", invoices.getNextOffset(), limit, ImmutableMap.<String, String>of(QUERY_INVOICE_WITH_ITEMS, withItems.toString(),
                                                                                QUERY_AUDIT, auditMode.getLevel().toString()));

        final AtomicReference<Map<UUID, AccountAuditLogs>> accountsAuditLogs = new AtomicReference<Map<UUID, AccountAuditLogs>>(new HashMap<UUID, AccountAuditLogs>());
        return buildStreamingPaginationResponse(invoices,
                                                new Function<Invoice, InvoiceJson>() {
                                                    @Override
                                                    public InvoiceJson apply(final Invoice invoice) {
                                                        // Cache audit logs per account
                                                        if (accountsAuditLogs.get().get(invoice.getAccountId()) == null) {
                                                            accountsAuditLogs.get().put(invoice.getAccountId(), auditUserApi.getAccountAuditLogs(invoice.getAccountId(), auditMode.getLevel(), tenantContext));
                                                        }
                                                        return new InvoiceJson(invoice, withItems, accountsAuditLogs.get().get(invoice.getAccountId()));
                                                    }
                                                },
                                                nextPageUri
                                               );
    }

    @Timed
    @GET
    @Path("/" + SEARCH + "/{searchKey:" + ANYTHING_PATTERN + "}")
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Search invoices", response = InvoiceJson.class, responseContainer = "List")
    @ApiResponses(value = {})
    public Response searchInvoices(@PathParam("searchKey") final String searchKey,
                                   @QueryParam(QUERY_SEARCH_OFFSET) @DefaultValue("0") final Long offset,
                                   @QueryParam(QUERY_SEARCH_LIMIT) @DefaultValue("100") final Long limit,
                                   @QueryParam(QUERY_INVOICE_WITH_ITEMS) @DefaultValue("false") final Boolean withItems,
                                   @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws SubscriptionApiException {
        final TenantContext tenantContext = context.createContext(request);
        final Pagination<Invoice> invoices = invoiceApi.searchInvoices(searchKey, offset, limit, tenantContext);
        final URI nextPageUri = uriBuilder.nextPage(InvoiceResource.class, "searchInvoices", invoices.getNextOffset(), limit, ImmutableMap.<String, String>of("searchKey", searchKey,
                                                                                QUERY_INVOICE_WITH_ITEMS, withItems.toString(),
                                                                                QUERY_AUDIT, auditMode.getLevel().toString()));
        final AtomicReference<Map<UUID, AccountAuditLogs>> accountsAuditLogs = new AtomicReference<Map<UUID, AccountAuditLogs>>(new HashMap<UUID, AccountAuditLogs>());
        return buildStreamingPaginationResponse(invoices,
                                                new Function<Invoice, InvoiceJson>() {
                                                    @Override
                                                    public InvoiceJson apply(final Invoice invoice) {
                                                        // Cache audit logs per account
                                                        if (accountsAuditLogs.get().get(invoice.getAccountId()) == null) {
                                                            accountsAuditLogs.get().put(invoice.getAccountId(), auditUserApi.getAccountAuditLogs(invoice.getAccountId(), auditMode.getLevel(), tenantContext));
                                                        }
                                                        return new InvoiceJson(invoice, withItems, accountsAuditLogs.get().get(invoice.getAccountId()));
                                                    }
                                                },
                                                nextPageUri
                                               );
    }

    @Timed
    @POST
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Trigger an invoice generation", response = InvoiceJson.class)
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
    public Response createFutureInvoice(@QueryParam(QUERY_ACCOUNT_ID) final String accountId,
                                        @QueryParam(QUERY_TARGET_DATE) final String targetDate,
                                        @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                        @HeaderParam(HDR_REASON) final String reason,
                                        @HeaderParam(HDR_COMMENT) final String comment,
                                        @javax.ws.rs.core.Context final HttpServletRequest request,
                                        @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
        final LocalDate inputDate = toLocalDate(UUID.fromString(accountId), targetDate, callContext);

        try {
            final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, null,
                                                                                callContext);
            return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", generatedInvoice.getId());
        } catch (InvoiceApiException e) {
            if (e.getCode() == ErrorCode.INVOICE_NOTHING_TO_DO.getCode()) {
                return Response.status(Status.NOT_FOUND).build();
            }
            throw e;
        }
    }

    @Timed
    @POST
    @Path("/" + DRY_RUN)
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Generate a dryRun invoice", response = InvoiceJson.class)
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or target datetime supplied")})
    public Response generateDryRunInvoice(@Nullable final InvoiceDryRunJson dryRunSubscriptionSpec,
                                          @QueryParam(QUERY_ACCOUNT_ID) final String accountId,
                                          @Nullable @QueryParam(QUERY_TARGET_DATE) final String targetDate,
                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                          @HeaderParam(HDR_REASON) final String reason,
                                          @HeaderParam(HDR_COMMENT) final String comment,
                                          @javax.ws.rs.core.Context final HttpServletRequest request,
                                          @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
        final LocalDate inputDate;
        if (dryRunSubscriptionSpec != null) {
            if (DryRunType.UPCOMING_INVOICE.name().equals(dryRunSubscriptionSpec.getDryRunType())) {
                inputDate = null;
            } else if (DryRunType.SUBSCRIPTION_ACTION.name().equals(dryRunSubscriptionSpec.getDryRunType()) && dryRunSubscriptionSpec.getEffectiveDate() != null) {
                inputDate = dryRunSubscriptionSpec.getEffectiveDate();
            } else {
                inputDate = toLocalDate(UUID.fromString(accountId), targetDate, callContext);
            }
        } else {
            inputDate = toLocalDate(UUID.fromString(accountId), targetDate, callContext);
        }

        // Passing a null or empty body means we are trying to generate an invoice with a (future) targetDate
        // On the other hand if body is not null, we are attempting a dryRun subscription operation
        if (dryRunSubscriptionSpec != null && dryRunSubscriptionSpec.getDryRunAction() != null) {
            if (SubscriptionEventType.START_BILLING.toString().equals(dryRunSubscriptionSpec.getDryRunAction())) {
                verifyNonNullOrEmpty(dryRunSubscriptionSpec.getProductName(), "DryRun subscription product category should be specified");
                verifyNonNullOrEmpty(dryRunSubscriptionSpec.getBillingPeriod(), "DryRun subscription billingPeriod should be specified");
                verifyNonNullOrEmpty(dryRunSubscriptionSpec.getProductCategory(), "DryRun subscription product category should be specified");
                if (dryRunSubscriptionSpec.getProductCategory().equals(ProductCategory.ADD_ON)) {
                    verifyNonNullOrEmpty(dryRunSubscriptionSpec.getBundleId(), "DryRun bundle ID should be specified");
                }
            } else if (SubscriptionEventType.CHANGE.toString().equals(dryRunSubscriptionSpec.getDryRunAction())) {
                verifyNonNullOrEmpty(dryRunSubscriptionSpec.getProductName(), "DryRun subscription product category should be specified");
                verifyNonNullOrEmpty(dryRunSubscriptionSpec.getBillingPeriod(), "DryRun subscription billingPeriod should be specified");
                verifyNonNullOrEmpty(dryRunSubscriptionSpec.getSubscriptionId(), "DryRun subscriptionID should be specified");
            } else if (SubscriptionEventType.STOP_BILLING.toString().equals(dryRunSubscriptionSpec.getDryRunAction())) {
                verifyNonNullOrEmpty(dryRunSubscriptionSpec.getSubscriptionId(), "DryRun subscriptionID should be specified");
            }
        }

        final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);

        final DryRunArguments dryRunArguments = new DefaultDryRunArguments(dryRunSubscriptionSpec, account.getTimeZone(), account.getCurrency(), clock);
        try {
            final Invoice generatedInvoice = invoiceApi.triggerInvoiceGeneration(UUID.fromString(accountId), inputDate, dryRunArguments,
                                                                                callContext);
            return Response.status(Status.OK).entity(new InvoiceJson(generatedInvoice, true, null)).build();
        } catch (InvoiceApiException e) {
            if (e.getCode() == ErrorCode.INVOICE_NOTHING_TO_DO.getCode()) {
                return Response.status(Status.NOT_FOUND).build();
            }
            throw e;
        }
    }

    @Timed
    @DELETE
    @Path("/{invoiceId:" + UUID_PATTERN + "}" + "/{invoiceItemId:" + UUID_PATTERN + "}/cba")
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Delete a CBA item")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"),
                           @ApiResponse(code = 404, message = "Account or invoice not found")})
    public Response deleteCBA(@PathParam("invoiceId") final String invoiceId,
                              @PathParam("invoiceItemId") final String invoiceItemId,
                              @QueryParam(QUERY_ACCOUNT_ID) final String accountId,
                              @HeaderParam(HDR_CREATED_BY) final String createdBy,
                              @HeaderParam(HDR_REASON) final String reason,
                              @HeaderParam(HDR_COMMENT) final String comment,
                              @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, InvoiceApiException {
        final CallContext callContext = context.createContext(createdBy, reason, comment, request);

        final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);

        invoiceApi.deleteCBA(account.getId(), UUID.fromString(invoiceId), UUID.fromString(invoiceItemId), callContext);

        return Response.status(Status.OK).build();
    }

    @Timed
    @POST
    @Path("/{invoiceId:" + UUID_PATTERN + "}")
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Adjust an invoice item")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id, invoice id or invoice item id supplied"),
                           @ApiResponse(code = 404, message = "Invoice not found")})
    public Response adjustInvoiceItem(final InvoiceItemJson json,
                                      @PathParam("invoiceId") final String invoiceId,
                                      @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
                                      @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                      @HeaderParam(HDR_REASON) final String reason,
                                      @HeaderParam(HDR_COMMENT) final String comment,
                                      @javax.ws.rs.core.Context final HttpServletRequest request,
                                      @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, InvoiceApiException {
        verifyNonNullOrEmpty(json, "InvoiceItemJson body should be specified");
        verifyNonNullOrEmpty(json.getAccountId(), "InvoiceItemJson accountId needs to be set",
                             json.getInvoiceItemId(), "InvoiceItemJson invoiceItemId needs to be set");

        final CallContext callContext = context.createContext(createdBy, reason, comment, request);

        final UUID accountId = UUID.fromString(json.getAccountId());
        final LocalDate requestedDate = toLocalDate(accountId, requestedDateTimeString, callContext);
        final InvoiceItem adjustmentItem;
        if (json.getAmount() == null) {
            adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId,
                                                                    UUID.fromString(invoiceId),
                                                                    UUID.fromString(json.getInvoiceItemId()),
                                                                    requestedDate,
                                                                    callContext);
        } else {
            adjustmentItem = invoiceApi.insertInvoiceItemAdjustment(accountId,
                                                                    UUID.fromString(invoiceId),
                                                                    UUID.fromString(json.getInvoiceItemId()),
                                                                    requestedDate,
                                                                    json.getAmount(),
                                                                    json.getCurrency(),
                                                                    callContext);
        }

        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, "getInvoice", adjustmentItem.getInvoiceId());
    }

    @Timed
    @POST
    @Produces(APPLICATION_JSON)
    @Consumes(APPLICATION_JSON)
    @Path("/" + CHARGES + "/{accountId:" + UUID_PATTERN + "}")
    @ApiOperation(value = "Create external charge(s)", response = InvoiceItemJson.class, responseContainer = "List")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id supplied"),
                           @ApiResponse(code = 404, message = "Account not found")})
    public Response createExternalCharges(final Iterable<InvoiceItemJson> externalChargesJson,
                                          @PathParam("accountId") final String accountId,
                                          @QueryParam(QUERY_REQUESTED_DT) final String requestedDateTimeString,
                                          @QueryParam(QUERY_PAY_INVOICE) @DefaultValue("false") final Boolean payInvoice,
                                          @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                          @HeaderParam(HDR_REASON) final String reason,
                                          @HeaderParam(HDR_COMMENT) final String comment,
                                          @javax.ws.rs.core.Context final UriInfo uriInfo,
                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws AccountApiException, InvoiceApiException, PaymentApiException {
        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
        final CallContext callContext = context.createContext(createdBy, reason, comment, request);

        final Account account = accountUserApi.getAccountById(UUID.fromString(accountId), callContext);
        final Iterable<InvoiceItemJson> sanitizedExternalChargesJson = cloneRefundItemsWithValidCurrency(account.getCurrency(), externalChargesJson);

        // Get the effective date of the external charge, in the account timezone
        final LocalDate requestedDate = toLocalDate(account, requestedDateTimeString, callContext);

        final Iterable<InvoiceItem> externalCharges = Iterables.<InvoiceItemJson, InvoiceItem>transform(sanitizedExternalChargesJson,
                                                                                new Function<InvoiceItemJson, InvoiceItem>() {
                                                                                @Override
                                                                                public InvoiceItem apply(final InvoiceItemJson invoiceItemJson) {
                                                                                return invoiceItemJson.toInvoiceItem();
                                                                                }
                                                                                }
                                                                                );
        final List<InvoiceItem> createdExternalCharges = invoiceApi.insertExternalCharges(account.getId(), requestedDate, externalCharges, callContext);

        if (payInvoice) {
            final Collection<UUID> paidInvoices = new HashSet<UUID>();
            for (final InvoiceItem externalCharge : createdExternalCharges) {
                if (!paidInvoices.contains(externalCharge.getInvoiceId())) {
                    paidInvoices.add(externalCharge.getInvoiceId());
                    final Invoice invoice = invoiceApi.getInvoice(externalCharge.getInvoiceId(), callContext);
                    createPurchaseForInvoice(account, invoice.getId(), invoice.getBalance(), account.getPaymentMethodId(), false, pluginProperties, callContext);
                }
            }
        }

        final List<InvoiceItemJson> createdExternalChargesJson = Lists.<InvoiceItem, InvoiceItemJson>transform(createdExternalCharges,
                                                                                new Function<InvoiceItem, InvoiceItemJson>() {
                                                                                @Override
                                                                                public InvoiceItemJson apply(final InvoiceItem input) {
                                                                                return new InvoiceItemJson(input);
                                                                                }
                                                                                }
                                                                                );
        return Response.status(Status.OK).entity(createdExternalChargesJson).build();
    }

    private Iterable<InvoiceItemJson> cloneRefundItemsWithValidCurrency(final Currency accountCurrency, final Iterable<InvoiceItemJson> inputItems) throws InvoiceApiException {
        try {
            return Iterables.transform(inputItems, new Function<InvoiceItemJson, InvoiceItemJson>() {
                @Override
                public InvoiceItemJson apply(final InvoiceItemJson input) {
                    if (input.getCurrency() != null) {
                        if (!input.getCurrency().equals(accountCurrency)) {
                            throw new IllegalArgumentException(input.getCurrency().toString());
                        }
                        return input;
                    } else {
                        return new InvoiceItemJson(null,
                                                   input.getInvoiceId(),
                                                   null, input.getAccountId(),
                                                   input.getBundleId(),
                                                   input.getSubscriptionId(),
                                                   input.getPlanName(),
                                                   input.getPhaseName(),
                                                   input.getUsageName(),
                                                   input.getItemType(),
                                                   input.getDescription(),
                                                   input.getStartDate(),
                                                   input.getEndDate(),
                                                   input.getAmount(),
                                                   accountCurrency,
                                                   null);
                    }
                }
            });
        } catch (IllegalArgumentException e) {
            throw new InvoiceApiException(ErrorCode.CURRENCY_INVALID, accountCurrency, e.getMessage());
        }
    }

    @Timed
    @GET
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + PAYMENTS)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Retrieve payments associated with an invoice", response = InvoicePaymentJson.class, responseContainer = "List")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                           @ApiResponse(code = 404, message = "Invoice not found")})
    public Response getPayments(@PathParam("invoiceId") final String invoiceId,
                                @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo,
                                @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, InvoiceApiException {

        final TenantContext tenantContext = context.createContext(request);
        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), tenantContext);

        // Extract unique set of paymentId for this invoice
        final Set<UUID> invoicePaymentIds = ImmutableSet.copyOf(Iterables.transform(invoice.getPayments(), new Function<InvoicePayment, UUID>() {
            @Override
            public UUID apply(final InvoicePayment input) {
                return input.getPaymentId();
            }
        }));
        if (invoicePaymentIds.isEmpty()) {
            return Response.status(Status.OK).entity(ImmutableList.<InvoicePaymentJson>of()).build();
        }

        final List<Payment> payments = new ArrayList<Payment>();
        for (final UUID paymentId : invoicePaymentIds) {
            final Payment payment = paymentApi.getPayment(paymentId, withPluginInfo, ImmutableList.<PluginProperty>of(), tenantContext);
            payments.add(payment);
        }

        final Iterable<InvoicePaymentJson> result = INVOICE_PAYMENT_ORDERING.sortedCopy(Iterables.transform(payments, new Function<Payment, InvoicePaymentJson>() {
            @Override
            public InvoicePaymentJson apply(final Payment input) {
                return new InvoicePaymentJson(input, invoice.getId(), null);
            }
        }));
        return Response.status(Status.OK).entity(result).build();
    }

    @Timed
    @POST
    @Produces(APPLICATION_JSON)
    @Consumes(APPLICATION_JSON)
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + PAYMENTS)
    @ApiOperation(value = "Trigger a payment for invoice")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid account id or invoice id supplied"),
                           @ApiResponse(code = 404, message = "Account not found")})
    public Response createInstantPayment(final InvoicePaymentJson payment,
                                         @QueryParam(QUERY_PAYMENT_EXTERNAL) @DefaultValue("false") final Boolean externalPayment,
                                         @QueryParam(QUERY_PLUGIN_PROPERTY) final List<String> pluginPropertiesString,
                                         @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                         @HeaderParam(HDR_REASON) final String reason,
                                         @HeaderParam(HDR_COMMENT) final String comment,
                                         @javax.ws.rs.core.Context final HttpServletRequest request,
                                         @javax.ws.rs.core.Context final UriInfo uriInfo) throws AccountApiException, PaymentApiException {
        verifyNonNullOrEmpty(payment, "InvoicePaymentJson body should be specified");
        verifyNonNullOrEmpty(payment.getAccountId(), "InvoicePaymentJson accountId needs to be set",
                             payment.getTargetInvoiceId(), "InvoicePaymentJson targetInvoiceId needs to be set",
                             payment.getPurchasedAmount(), "InvoicePaymentJson purchasedAmount needs to be set");
        Preconditions.checkArgument(!externalPayment || payment.getPaymentMethodId() == null, "InvoicePaymentJson should not contain a paymwentMethodId when this is an external payment");

        final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
        final CallContext callContext = context.createContext(createdBy, reason, comment, request);

        final Account account = accountUserApi.getAccountById(UUID.fromString(payment.getAccountId()), callContext);
        final UUID paymentMethodId = externalPayment ? null :
                                     (payment.getPaymentMethodId() != null ? UUID.fromString(payment.getPaymentMethodId()) : account.getPaymentMethodId());

        final UUID invoiceId = UUID.fromString(payment.getTargetInvoiceId());
        final Payment result = createPurchaseForInvoice(account, invoiceId, payment.getPurchasedAmount(), paymentMethodId, externalPayment, pluginProperties, callContext);
        // STEPH should that live in InvoicePayment instead?
        return uriBuilder.buildResponse(uriInfo, InvoicePaymentResource.class, "getInvoicePayment", result.getId());
    }

    @Timed
    @POST
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + EMAIL_NOTIFICATIONS)
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Trigger an email notification for invoice")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                           @ApiResponse(code = 404, message = "Account or invoice not found")})
    public Response triggerEmailNotificationForInvoice(@PathParam("invoiceId") final String invoiceId,
                                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                                       @HeaderParam(HDR_REASON) final String reason,
                                                       @HeaderParam(HDR_COMMENT) final String comment,
                                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, AccountApiException {
        final CallContext callContext = context.createContext(createdBy, reason, comment, request);

        final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), callContext);
        if (invoice == null) {
            throw new InvoiceApiException(ErrorCode.INVOICE_NOT_FOUND, invoiceId);
        }

        final Account account = accountUserApi.getAccountById(invoice.getAccountId(), callContext);

        // Send the email (synchronous send)
        invoiceNotifier.notify(account, invoice, callContext);

        return Response.status(Status.OK).build();
    }

    @Timed
    @GET
    @Path("/" + INVOICE_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
    @Produces(TEXT_PLAIN)
    @ApiOperation(value = "Retrieves the invoice translation for the tenant", response = String.class, hidden = true)
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid locale supplied"),
                           @ApiResponse(code = 404, message = "Translation not found")})
    public Response getInvoiceTranslation(@PathParam("locale") final String localeStr,
                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
        return getTemplateResource(localeStr, TenantKey.INVOICE_TRANSLATION_, request);
    }

    @Timed
    @POST
    @Produces(TEXT_PLAIN)
    @Consumes(TEXT_PLAIN)
    @Path("/" + INVOICE_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
    @ApiOperation(value = "Upload the invoice translation for the tenant")
    @ApiResponses(value = {})
    public Response uploadInvoiceTranslation(final String invoiceTranslation,
                                             @PathParam("locale") final String localeStr,
                                             @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                             @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                             @HeaderParam(HDR_REASON) final String reason,
                                             @HeaderParam(HDR_COMMENT) final String comment,
                                             @javax.ws.rs.core.Context final HttpServletRequest request,
                                             @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
        return uploadTemplateResource(invoiceTranslation,
                                      localeStr,
                                      deleteIfExists,
                                      TenantKey.INVOICE_TRANSLATION_,
                                      "getInvoiceTranslation",
                                      createdBy,
                                      reason,
                                      comment,
                                      request,
                                      uriInfo);
    }

    @Timed
    @GET
    @Path("/" + INVOICE_CATALOG_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
    @Produces(TEXT_PLAIN)
    @ApiOperation(value = "Retrieves the catalog translation for the tenant", response = String.class, hidden = true)
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid locale supplied"),
                           @ApiResponse(code = 404, message = "Template not found")})
    public Response getCatalogTranslation(@PathParam("locale") final String localeStr,
                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
        return getTemplateResource(localeStr, TenantKey.CATALOG_TRANSLATION_, request);
    }

    @Timed
    @POST
    @Produces(TEXT_PLAIN)
    @Consumes(TEXT_PLAIN)
    @Path("/" + INVOICE_CATALOG_TRANSLATION + "/{locale:" + ANYTHING_PATTERN + "}/")
    @ApiOperation(value = "Upload the catalog translation for the tenant")
    @ApiResponses(value = {})
    public Response uploadCatalogTranslation(final String catalogTranslation,
                                             @PathParam("locale") final String localeStr,
                                             @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                             @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                             @HeaderParam(HDR_REASON) final String reason,
                                             @HeaderParam(HDR_COMMENT) final String comment,
                                             @javax.ws.rs.core.Context final HttpServletRequest request,
                                             @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {

        return uploadTemplateResource(catalogTranslation,
                                      localeStr,
                                      deleteIfExists,
                                      TenantKey.CATALOG_TRANSLATION_,
                                      "getCatalogTranslation",
                                      createdBy,
                                      reason,
                                      comment,
                                      request,
                                      uriInfo);
    }

    @Timed
    @GET
    @Path("/" + INVOICE_TEMPLATE)
    @Produces(TEXT_HTML)
    @ApiOperation(value = "Retrieves the invoice template for the tenant", response = String.class, hidden = true)
    @ApiResponses(value = {@ApiResponse(code = 404, message = "Template not found")})
    public Response getInvoiceTemplate(@javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
        return getTemplateResource(null, TenantKey.INVOICE_TEMPLATE, request);
    }

    @Timed
    @POST
    @Produces(TEXT_HTML)
    @Consumes(TEXT_HTML)
    @Path("/" + INVOICE_TEMPLATE)
    @ApiOperation(value = "Upload the invoice template for the tenant")
    @ApiResponses(value = {})
    public Response uploadInvoiceTemplate(final String catalogTranslation,
                                          @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                          @HeaderParam(HDR_REASON) final String reason,
                                          @HeaderParam(HDR_COMMENT) final String comment,
                                          @javax.ws.rs.core.Context final HttpServletRequest request,
                                          @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
        return uploadTemplateResource(catalogTranslation,
                                      null,
                                      deleteIfExists,
                                      TenantKey.INVOICE_TEMPLATE,
                                      "getInvoiceTemplate",
                                      createdBy,
                                      reason,
                                      comment,
                                      request,
                                      uriInfo);
    }

    @Timed
    @GET
    @Path("/" + INVOICE_MP_TEMPLATE)
    @Produces(TEXT_HTML)
    @ApiOperation(value = "Retrieves the manualPay invoice template for the tenant", response = String.class, hidden = true)
    @ApiResponses(value = {@ApiResponse(code = 404, message = "Template not found")})
    public Response getInvoiceMPTemplate(@PathParam("locale") final String localeStr,
                                         @javax.ws.rs.core.Context final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
        return getTemplateResource(null, TenantKey.INVOICE_MP_TEMPLATE, request);
    }

    @Timed
    @POST
    @Produces(TEXT_HTML)
    @Consumes(TEXT_HTML)
    @Path("/" + INVOICE_MP_TEMPLATE)
    @ApiOperation(value = "Upload the manualPay invoice template for the tenant")
    @ApiResponses(value = {})
    public Response uploadInvoiceMPTemplate(final String catalogTranslation,
                                            @QueryParam(QUERY_DELETE_IF_EXISTS) @DefaultValue("false") final boolean deleteIfExists,
                                            @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                            @HeaderParam(HDR_REASON) final String reason,
                                            @HeaderParam(HDR_COMMENT) final String comment,
                                            @javax.ws.rs.core.Context final HttpServletRequest request,
                                            @javax.ws.rs.core.Context final UriInfo uriInfo) throws Exception {
        return uploadTemplateResource(catalogTranslation,
                                      null,
                                      deleteIfExists,
                                      TenantKey.INVOICE_MP_TEMPLATE,
                                      "getInvoiceMPTemplate",
                                      createdBy,
                                      reason,
                                      comment,
                                      request,
                                      uriInfo);
    }

    private Response uploadTemplateResource(final String templateResource,
                                            @Nullable final String localeStr,
                                            final boolean deleteIfExists,
                                            final TenantKey tenantKey,
                                            final String getMethodStr,
                                            final String createdBy,
                                            final String reason,
                                            final String comment,
                                            final HttpServletRequest request,
                                            final UriInfo uriInfo) throws Exception {
        final String tenantKeyStr;
        if (localeStr != null) {
            // Validation purpose:  Will throw bad stream
            final InputStream stream = new ByteArrayInputStream(templateResource.getBytes());
            new PropertyResourceBundle(stream);
            final Locale locale = localeStr != null ? LocaleUtils.toLocale(localeStr) : defaultLocale;
            tenantKeyStr = LocaleUtils.localeString(locale, tenantKey.toString());
        } else {
            tenantKeyStr = tenantKey.toString();
        }

        final CallContext callContext = context.createContext(createdBy, reason, comment, request);

        if (!tenantApi.getTenantValuesForKey(tenantKeyStr, callContext).isEmpty()) {
            if (deleteIfExists) {
                tenantApi.deleteTenantKey(tenantKeyStr, callContext);
            } else {
                return Response.status(Status.BAD_REQUEST).build();
            }
        }
        tenantApi.addTenantKeyValue(tenantKeyStr, templateResource, callContext);
        return uriBuilder.buildResponse(uriInfo, InvoiceResource.class, getMethodStr, localeStr);
    }

    private Response getTemplateResource(@Nullable final String localeStr,
                                         final TenantKey tenantKey,
                                         final HttpServletRequest request) throws InvoiceApiException, TenantApiException {
        final TenantContext tenantContext = context.createContext(request);
        final String tenantKeyStr = localeStr != null ?
                                    LocaleUtils.localeString(LocaleUtils.toLocale(localeStr), tenantKey.toString()) :
                                    tenantKey.toString();
        final List<String> result = tenantApi.getTenantValuesForKey(tenantKeyStr, tenantContext);
        return result.isEmpty() ? Response.status(Status.NOT_FOUND).build() : Response.status(Status.OK).entity(result.get(0)).build();
    }

    @Timed
    @GET
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Retrieve invoice custom fields", response = CustomFieldJson.class, responseContainer = "List")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
    public Response getCustomFields(@PathParam(ID_PARAM_NAME) final String id,
                                    @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                                    @javax.ws.rs.core.Context final HttpServletRequest request) {
        return super.getCustomFields(UUID.fromString(id), auditMode, context.createContext(request));
    }

    @Timed
    @POST
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Add custom fields to invoice")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
    public Response createCustomFields(@PathParam(ID_PARAM_NAME) final String id,
                                       final List<CustomFieldJson> customFields,
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                       @HeaderParam(HDR_REASON) final String reason,
                                       @HeaderParam(HDR_COMMENT) final String comment,
                                       @javax.ws.rs.core.Context final HttpServletRequest request,
                                       @javax.ws.rs.core.Context final UriInfo uriInfo) throws CustomFieldApiException {
        return super.createCustomFields(UUID.fromString(id), customFields,
                                        context.createContext(createdBy, reason, comment, request), uriInfo);
    }

    @Timed
    @DELETE
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Remove custom fields from invoice")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
    public Response deleteCustomFields(@PathParam(ID_PARAM_NAME) final String id,
                                       @QueryParam(QUERY_CUSTOM_FIELDS) final String customFieldList,
                                       @HeaderParam(HDR_CREATED_BY) final String createdBy,
                                       @HeaderParam(HDR_REASON) final String reason,
                                       @HeaderParam(HDR_COMMENT) final String comment,
                                       @javax.ws.rs.core.Context final HttpServletRequest request) throws CustomFieldApiException {
        return super.deleteCustomFields(UUID.fromString(id), customFieldList,
                                        context.createContext(createdBy, reason, comment, request));
    }

    @Timed
    @GET
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + TAGS)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Retrieve invoice tags", response = TagJson.class, responseContainer = "List")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied"),
                           @ApiResponse(code = 404, message = "Invoice not found")})
    public Response getTags(@PathParam(ID_PARAM_NAME) final String invoiceIdString,
                            @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode,
                            @QueryParam(QUERY_TAGS_INCLUDED_DELETED) @DefaultValue("false") final Boolean includedDeleted,
                            @javax.ws.rs.core.Context final HttpServletRequest request) throws TagDefinitionApiException, InvoiceApiException {
        final UUID invoiceId = UUID.fromString(invoiceIdString);
        final TenantContext tenantContext = context.createContext(request);
        final Invoice invoice = invoiceApi.getInvoice(invoiceId, tenantContext);
        return super.getTags(invoice.getAccountId(), invoiceId, auditMode, includedDeleted, tenantContext);
    }

    @Timed
    @POST
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + TAGS)
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Add tags to invoice")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
    public Response createTags(@PathParam(ID_PARAM_NAME) final String id,
                               @QueryParam(QUERY_TAGS) final String tagList,
                               @HeaderParam(HDR_CREATED_BY) final String createdBy,
                               @HeaderParam(HDR_REASON) final String reason,
                               @HeaderParam(HDR_COMMENT) final String comment,
                               @javax.ws.rs.core.Context final UriInfo uriInfo,
                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
        return super.createTags(UUID.fromString(id), tagList, uriInfo,
                                context.createContext(createdBy, reason, comment, request));
    }

    @Timed
    @DELETE
    @Path("/{invoiceId:" + UUID_PATTERN + "}/" + TAGS)
    @Consumes(APPLICATION_JSON)
    @Produces(APPLICATION_JSON)
    @ApiOperation(value = "Remove tags from invoice")
    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid invoice id supplied")})
    public Response deleteTags(@PathParam(ID_PARAM_NAME) final String id,
                               @QueryParam(QUERY_TAGS) final String tagList,
                               @HeaderParam(HDR_CREATED_BY) final String createdBy,
                               @HeaderParam(HDR_REASON) final String reason,
                               @HeaderParam(HDR_COMMENT) final String comment,
                               @javax.ws.rs.core.Context final HttpServletRequest request) throws TagApiException {
        return super.deleteTags(UUID.fromString(id), tagList,
                                context.createContext(createdBy, reason, comment, request));
    }

    @Override
    protected ObjectType getObjectType() {
        return ObjectType.INVOICE;
    }

    private static class DefaultDryRunArguments implements DryRunArguments {

        private final DryRunType dryRunType;
        private final SubscriptionEventType action;
        private final UUID subscriptionId;
        private final DateTime effectiveDate;
        private final PlanPhaseSpecifier specifier;
        private final UUID bundleId;
        private final BillingActionPolicy billingPolicy;
        private final List<PlanPhasePriceOverride> overrides;

        public DefaultDryRunArguments(final InvoiceDryRunJson input, final DateTimeZone accountTimeZone, final Currency currency, final Clock clock) {
            if (input == null) {
                this.dryRunType = DryRunType.TARGET_DATE;
                this.action = null;
                this.subscriptionId = null;
                this.effectiveDate = null;
                this.specifier = null;
                this.bundleId = null;
                this.billingPolicy = null;
                this.overrides = null;
            } else {
                this.dryRunType = input.getDryRunType() != null ? DryRunType.valueOf(input.getDryRunType()) : DryRunType.TARGET_DATE;
                this.action = input.getDryRunAction() != null ? SubscriptionEventType.valueOf(input.getDryRunAction()) : null;
                this.subscriptionId = input.getSubscriptionId() != null ? UUID.fromString(input.getSubscriptionId()) : null;
                this.bundleId = input.getBundleId() != null ? UUID.fromString(input.getBundleId()) : null;
                this.effectiveDate = input.getEffectiveDate() != null ? ClockUtil.computeDateTimeWithUTCReferenceTime(input.getEffectiveDate(), clock.getUTCNow().toLocalTime(), accountTimeZone, clock) : null;
                this.billingPolicy = input.getBillingPolicy() != null ? BillingActionPolicy.valueOf(input.getBillingPolicy()) : null;
                final PlanPhaseSpecifier planPhaseSpecifier = (input.getProductName() != null &&
                                                               input.getProductCategory() != null &&
                                                               input.getBillingPeriod() != null) ?
                                                              new PlanPhaseSpecifier(input.getProductName(),
                                                                                ProductCategory.valueOf(input.getProductCategory()),
                                                                                BillingPeriod.valueOf(input.getBillingPeriod()),
                                                                                input.getPriceListName(),
                                                                                input.getPhaseType() != null ? PhaseType.valueOf(input.getPhaseType()) : null) :
                                                              null;
                this.specifier = planPhaseSpecifier;
                this.overrides = input.getPriceOverrides() != null ?
                                 ImmutableList.copyOf(Iterables.transform(input.getPriceOverrides(), new Function<PhasePriceOverrideJson, PlanPhasePriceOverride>() {
                                     @Nullable
                                     @Override
                                     public PlanPhasePriceOverride apply(@Nullable final PhasePriceOverrideJson input) {
                                         if (input.getPhaseName() != null) {
                                             return new DefaultPlanPhasePriceOverride(input.getPhaseName(), currency, input.getFixedPrice(), input.getRecurringPrice());
                                         } else {
                                             return new DefaultPlanPhasePriceOverride(planPhaseSpecifier, currency, input.getFixedPrice(), input.getRecurringPrice());
                                         }
                                     }
                                 })) : ImmutableList.<PlanPhasePriceOverride>of();
            }
        }

        @Override
        public DryRunType getDryRunType() {
            return dryRunType;
        }

        @Override
        public PlanPhaseSpecifier getPlanPhaseSpecifier() {
            return specifier;
        }

        @Override
        public SubscriptionEventType getAction() {
            return action;
        }

        @Override
        public UUID getSubscriptionId() {
            return subscriptionId;
        }

        @Override
        public DateTime getEffectiveDate() {
            return effectiveDate;
        }

        @Override
        public UUID getBundleId() {
            return bundleId;
        }

        @Override
        public BillingActionPolicy getBillingActionPolicy() {
            return billingPolicy;
        }

        @Override
        public List<PlanPhasePriceOverride> getPlanPhasePriceOverrides() {
            return overrides;
        }
    }

}


text:
package org.apache.kafka.shell;

import net.sourceforge.argparse4j.ArgumentParsers;
import net.sourceforge.argparse4j.inf.ArgumentParser;
import net.sourceforge.argparse4j.inf.ArgumentParserException;
import net.sourceforge.argparse4j.inf.Namespace;
import net.sourceforge.argparse4j.inf.Subparser;
import net.sourceforge.argparse4j.inf.Subparsers;
import net.sourceforge.argparse4j.internal.HelpScreenException;
import org.jline.reader.Candidate;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.TreeMap;

/**
 * The commands for the Kafka metadata tool.
 */
public final class Commands {
    /**
     * A map from command names to command types.
     */
    static final NavigableMap<String, Type> TYPES;

    static {
        TreeMap<String, Type> typesMap = new TreeMap<>();
        for (Type type : Arrays.asList(
                CatCommandHandler.TYPE,
                CdCommandHandler.TYPE,
                ExitCommandHandler.TYPE,
                FindCommandHandler.TYPE,
                HelpCommandHandler.TYPE,
                HistoryCommandHandler.TYPE,
                LsCommandHandler.TYPE,
                ManCommandHandler.TYPE,
                PwdCommandHandler.TYPE)) {
            typesMap.put(type.name(), type);
        }
        TYPES = Collections.unmodifiableNavigableMap(typesMap);
    }

    /**
     * Command handler objects are instantiated with specific arguments to
     * execute commands.
     */
    public interface Handler {
        void run(Optional<InteractiveShell> shell,
                 PrintWriter writer,
                 MetadataNodeManager manager) throws Exception;
    }

    /**
     * An object which describes a type of command handler. This includes
     * information like its name, help text, and whether it should be accessible
     * from non-interactive mode.
     */
    public interface Type {
        String name();
        String description();
        boolean shellOnly();
        void addArguments(ArgumentParser parser);
        Handler createHandler(Namespace namespace);
        void completeNext(MetadataNodeManager nodeManager,
                          List<String> nextWords,
                          List<Candidate> candidates) throws Exception;
    }

    private final ArgumentParser parser;

    /**
     * Create the commands instance.
     *
     * @param addShellCommands  True if we should include the shell-only commands.
     */
    public Commands(boolean addShellCommands) {
        this.parser = ArgumentParsers.newArgumentParser("", false);
        Subparsers subparsers = this.parser.addSubparsers().dest("command");
        for (Type type : TYPES.values()) {
            if (addShellCommands || !type.shellOnly()) {
                Subparser subParser = subparsers.addParser(type.name());
                subParser.help(type.description());
                type.addArguments(subParser);
            }
        }
    }

    ArgumentParser parser() {
        return parser;
    }

    /**
     * Handle the given command.
     *
     * In general this function should not throw exceptions. Instead, it should
     * return ErroneousCommandHandler if the input was invalid.
     *
     * @param arguments     The command line arguments.
     * @return              The command handler.
     */
    public Handler parseCommand(List<String> arguments) {
        List<String> trimmedArguments = new ArrayList<>(arguments);
        while (true) {
            if (trimmedArguments.isEmpty()) {
                return new NoOpCommandHandler();
            }
            String last = trimmedArguments.get(trimmedArguments.size() - 1);
            if (!last.isEmpty()) {
                break;
            }
            trimmedArguments.remove(trimmedArguments.size() - 1);
        }
        Namespace namespace;
        try {
            namespace = parser.parseArgs(trimmedArguments.toArray(new String[0]));
        } catch (HelpScreenException e) {
            return new NoOpCommandHandler();
        } catch (ArgumentParserException e) {
            return new ErroneousCommandHandler(e.getMessage());
        }
        String command = namespace.get("command");
        if (!command.equals(trimmedArguments.get(0))) {
            return new ErroneousCommandHandler("invalid choice: '" +
                trimmedArguments.get(0) + "': did you mean '" + command + "'?");
        }
        Type type = TYPES.get(command);
        if (type == null) {
            return new ErroneousCommandHandler("Unknown command specified: " + command);
        } else {
            return type.createHandler(namespace);
        }
    }
}


text:
A Git subcommand to `mv` file like gsub in a repository

## Usage

```sh
$ git gsub-files READ WRITE
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

deleted:    README.md

Untracked files:
(use "git add <file>..." to include in what will be committed)

WRITEME.md

no changes added to commit (use "git add" and/or "git commit -a")
```

### `--add` option

Run `git mv` instead of `mv`.

```sh
$ git gsub-files READ WRITE --add
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)

renamed:    README.md -> WRITEME.md

no changes added to commit (use "git add" and/or "git commit -a")
```

## Instration

    $ gem install git-gsub-files

## See also

- [git-gsub](https://github.com/fujimura/git-gsub) A Git subcommand to do gsub in a repository
- [git-rename](https://github.com/fujimura/dotfiles/blob/master/bin/git-rename)

## Contributing

1. Fork it ( https://github.com/[my-github-username]/git-gsub-files/fork )
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request


text:
TIWO
====

Today I Worked On


text:
#include "net_caffe_convnet.h"
#include "imginputfileconn.h"
#include "mllibstrategy.h"

namespace dd
{

  /*- NetLayersCaffeConvnet -*/
  void NetLayersCaffeConvnet::parse_conv_layers(const std::vector<std::string> &layers,
						std::vector<std::pair<int,int>> &cr_layers,
						std::vector<int> &fc_layers)
  {
    const std::string cr_str = "CR";
    for (auto s: layers)
      {
	size_t pos = 0;
	if ((pos=s.find(cr_str))!=std::string::npos)
	  {
	    std::string ncr = s.substr(0,pos);
	    std::string crs = s.substr(pos+cr_str.size());
	    cr_layers.push_back(std::pair<int,int>(std::atoi(ncr.c_str()),std::atoi(crs.c_str())));
	  }
	else
	  {
	    try
	      {
		fc_layers.push_back(std::atoi(s.c_str()));
	      }
	    catch(std::exception &e)
	      {
		//TODO
		throw MLLibBadParamException("convnet template requires fully connected layers size to be specified as a string");
	      }
	  }
      }
  }

  void NetLayersCaffeConvnet::add_basic_block(caffe::NetParameter *net_param,
					      const std::string &bottom,
					      const std::string &top,
					      const int &nconv,
					      const int &num_output,
					      const int &kernel_size,
					      const int &pad,
					      const int &stride,
					      const std::string &activation,
					      const double &dropout_ratio,
					      const bool &bn,
					      const int &pl_kernel_size,
					      const int &pl_stride,
					      const std::string &pl_type,
					      const int &kernel_w,
					      const int &kernel_h,
					      const int &pl_kernel_w,
					      const int &pl_kernel_h,
					      const int &pl_stride_w,
					      const int &pl_stride_h)
  {
    std::string top_conv;
    std::string bottom_conv = bottom;
    for (int c=0;c<nconv;c++)
      {
	top_conv = top + "_conv_" + std::to_string(c);
	add_conv(net_param,bottom_conv,top_conv,num_output,kernel_size,pad,stride,kernel_w,kernel_h,0,0,top_conv);
	if (bn)
	  {
	    add_bn(net_param,top_conv);
	    add_act(net_param,top_conv,activation);
	  }
	else if (dropout_ratio > 0.0) // though in general, no dropout between convolutions
	  {
	    add_act(net_param,top_conv,activation);
	    if (c != nconv-1)
	      add_dropout(net_param,top_conv,dropout_ratio);
	  }
	else add_act(net_param,top_conv,activation);
	bottom_conv = top_conv;
      }
    // pooling
    add_pooling(net_param,top_conv,top,pl_kernel_size,pl_stride,pl_type,pl_kernel_w,pl_kernel_h,pl_stride_w,pl_stride_h);
    /*if (dropout_ratio > 0.0 && !bn)
      add_dropout(net_param,top,dropout_ratio);*/
  }

  void NetLayersCaffeConvnet::configure_net(const APIData &ad_mllib)
  {
    int nclasses = -1;
    if (ad_mllib.has("nclasses"))
      nclasses = ad_mllib.get("nclasses").get<int>();
    int ntargets = -1;
    if (ad_mllib.has("ntargets"))
      ntargets = ad_mllib.get("ntargets").get<int>();
    bool regression = false;
    if (ad_mllib.has("regression"))
      regression = ad_mllib.get("regression").get<bool>();
    bool flat1dconv = false;
    if (ad_mllib.has("flat1dconv"))
      flat1dconv = ad_mllib.get("flat1dconv").get<bool>();

    std::vector<std::string> layers;
    std::string activation = CaffeCommon::set_activation(ad_mllib);
    double dropout = 0.5;
    if (ad_mllib.has("layers"))
      layers = ad_mllib.get("layers").get<std::vector<std::string>>();
    //TODO: else raise exception
    std::vector<std::pair<int,int>> cr_layers;
    std::vector<int> fc_layers;
    parse_conv_layers(layers,cr_layers,fc_layers);
    if (ad_mllib.has("dropout"))
      dropout = ad_mllib.get("dropout").get<double>();
    bool bn = false;
    if (ad_mllib.has("bn"))
      bn = ad_mllib.get("bn").get<bool>();
    int conv_kernel_size = 3;
    int conv1d_early_kernel_size = 7;
    std::string bottom = "data";
    int width = -1;
    if (flat1dconv)
      width = this->_net_params->mutable_layer(1)->mutable_memory_data_param()->width();
    //TODO: support for embed layer in inputs
    for (size_t l=0;l<cr_layers.size();l++)
      {
	std::string top = "ip" + std::to_string(l);
	if (!flat1dconv)
	  {
	    add_basic_block(this->_net_params,bottom,top,cr_layers.at(l).first,cr_layers.at(l).second,
			    conv_kernel_size,0,1,activation,0.0,bn,2,2,"MAX");
	    add_basic_block(this->_dnet_params,bottom,top,cr_layers.at(l).first,cr_layers.at(l).second,
			    conv_kernel_size,0,1,activation,0.0,bn,2,2,"MAX");
	  }
	else
	  {
	    add_basic_block(this->_net_params,bottom,top,cr_layers.at(l).first,cr_layers.at(l).second,
			    0,0,1,activation,0.0,bn,0,0,"MAX",bottom=="data"?width:1,l<2?conv1d_early_kernel_size:conv_kernel_size,1,3,1,3);
	    add_basic_block(this->_dnet_params,bottom,top,cr_layers.at(l).first,cr_layers.at(l).second,
			    0,0,1,activation,0.0,bn,0,0,"MAX",bottom=="data"?width:1,l<2?conv1d_early_kernel_size:conv_kernel_size,1,3,1,3);
	  }
	bottom = top;
      }
    if (flat1dconv)
      {
	std::string top = "reshape0";
	caffe::ReshapeParameter r_param;
	r_param.mutable_shape()->add_dim(0);
	r_param.mutable_shape()->add_dim(-1);
	add_reshape(this->_net_params,bottom,top,r_param);
	add_reshape(this->_dnet_params,bottom,top,r_param);
	bottom = top;
      }
    int l = 0;
    for (auto fc: fc_layers)
      {
	std::string top = "fc" + std::to_string(fc) + "_" + std::to_string(l);
	NetLayersCaffeMLP::add_basic_block(this->_net_params,bottom,top,fc,activation,dropout,bn,false);
	NetLayersCaffeMLP::add_basic_block(this->_dnet_params,bottom,top,fc,activation,0.0,bn,false);
	bottom = top;
	++l;
      }
    if (regression)
      {
	add_euclidean_loss(this->_net_params,bottom,"label","losst",ntargets);
	add_euclidean_loss(this->_net_params,bottom,"","loss",ntargets,true);
      }
    else
      {
	add_softmax(this->_net_params,bottom,"label","losst",nclasses > 0 ? nclasses : ntargets);
	add_softmax(this->_dnet_params,bottom,"","loss",nclasses > 0 ? nclasses : ntargets,true);
      }
  }

  template class NetCaffe<NetInputCaffe<ImgCaffeInputFileConn>,NetLayersCaffeConvnet,NetLossCaffe>;
  template class NetCaffe<NetInputCaffe<CSVCaffeInputFileConn>,NetLayersCaffeConvnet,NetLossCaffe>;
  template class NetCaffe<NetInputCaffe<TxtCaffeInputFileConn>,NetLayersCaffeConvnet,NetLossCaffe>;
  template class NetCaffe<NetInputCaffe<SVMCaffeInputFileConn>,NetLayersCaffeConvnet,NetLossCaffe>;
}


text:
$(function () {
  $('#fileupload').fileupload({
    //maxChunkSize: 255, // 255 bytes
      add: function(e, data) {
        var uploadErrors = [];
        var acceptFileTypes = "text/plain";
        if(data.originalFiles[0]['type'].length && acceptFileTypes !== data.originalFiles[0]['type'])
        {
          uploadErrors.push('Not an accepted file type');
        }
        //30MB limit on size
        if(data.originalFiles[0]['size'].length && data.originalFiles[0]['size'] > 30000000)
        {
          uploadErrors.push('Filesize is too big');
        }
        if (data.originalFiles[0].name.split(".")[data.originalFiles[0].name.split(".").length - 1] !== "txt")
        {
          uploadErrors.push('File extension needs to be .txt');
        }
        if(uploadErrors.length > 0)
        {
          $('#progress').html("File not supported
"
              + uploadErrors.join("
"));
        }
        else
        {
          data.submit();
        }
      },
      dataType: 'json',
      done: function (e, data) {
        $('#result').html("");
          $.each(data.result.files, function (index, file) {
            if(file.reportUrl) {
              $('#result').append(
                  "
Upload Successful. View report NOW!
"
              );
              $('#progress').html(
                  '100% complete'
              );
              $('#progressBar').css(
                  'width',
                  '100%'
              );
            } else {
              $('#result').append(
              "
File "+file.name+" Upload failed Try again later!.
"
            );
            }
          });
      },
      progressall: function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10) - 1;
        $('#progressBar').css(
            'width',
            progress + '%'
        );
        $('#progress').html(
            progress + '% complete'
        );
      }
  });
});