class MusicSessionManager < BaseManager

  def initialize(options={})
    super(options)
    @log = Logging.logger[self]
  end

  def create(music_session, user, client_id, description, musician_access, approval_required, fan_chat, fan_access, band, genres, tracks, legal_terms, audio_latency)
    return_value = nil

    time = Benchmark.realtime do
      ActiveRecord::Base.transaction do

        # we need to lock the icecast server in this transaction for writing, to make sure thath IcecastConfigWriter
        # doesn't dumpXML as we are changing the server's configuraion
        icecast_server = IcecastServer.find_best_server_for_user(user) if fan_access
        icecast_server.lock! if icecast_server

        # check if we are connected to rabbitmq
        active_music_session = ActiveMusicSession.new
        active_music_session.id = music_session.id # copy the .id from music_session to active_music_session
        active_music_session.creator = user
        active_music_session.school_id = user.school_id
        active_music_session.is_platform_instructor = user.is_platform_instructor

        if fan_access
          # create an icecast mount since regular users can listen in to the broadcast
          active_music_session.mount = IcecastMount.build_session_mount(music_session, active_music_session, icecast_server)
        end

        active_music_session.save

        unless active_music_session.errors.any?
          music_session.started_at = active_music_session.created_at
          music_session.save(:validate => false)

          # save session parameters for next session
          User.save_session_settings(user, music_session)

          # auto-join this user into the newly created session
          as_musician = true
          connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)

          unless connection.errors.any?
            user.update_progression_field(:first_music_session_at)
            MusicSessionUserHistory.save(active_music_session.id, user.id, client_id, tracks)

            # only send this notification if it's a band session
            unless band.nil?
              Notification.send_band_session_join(active_music_session, band)
            end

            return_value = active_music_session
          else
            return_value = connection
            # rollback the transaction to make sure nothing is disturbed in the database
            raise ActiveRecord::Rollback
          end
        else
          return_value = active_music_session
          # rollback the transaction to make sure nothing is disturbed in the database
          raise ActiveRecord::Rollback
        end
      end
    end

    if time > 2
      @log.warn "creating a music session took #{time*1000} milliseconds"
    end

    return_value
  end

  # Update the session. If a field is left out (meaning, it's set to nil), it's not updated.
  def update(current_user, music_session, name, description, genre, language, musician_access, approval_required, fan_chat, fan_access, session_controller_id, friends_can_join)

    music_session.name = name unless name.nil?
    music_session.description = description unless description.nil?
    music_session.genre = genre unless genre.nil?
    music_session.language = language unless language.nil?
    music_session.musician_access = musician_access unless musician_access.nil?
    music_session.approval_required = approval_required unless approval_required.nil?
    music_session.fan_chat = fan_chat unless fan_chat.nil?
    music_session.fan_access = fan_access unless fan_access.nil?
    music_session.friends_can_join = friends_can_join unless friends_can_join.nil?
    session_controller = User.find(session_controller_id) if session_controller_id.present?
    should_tick = music_session.set_session_controller(current_user, session_controller)
    music_session.save

    if should_tick && music_session.active_music_session
      music_session.active_music_session.tick_track_changes
      Notification.send_tracks_changed(music_session.active_music_session)
    end

    music_session
  end

  def participant_create(user, music_session_id, client_id, as_musician, tracks, audio_latency)
    connection = nil
    music_session = nil
    active_music_session = nil
    send_track_changed = false
    ActiveRecord::Base.transaction do

      active_music_session = ActiveMusicSession.find(music_session_id)

      active_music_session.with_lock do # VRFS-1297
        active_music_session.tick_track_changes
        send_track_changed = true
        connection = ConnectionManager.new.join_music_session(user, client_id, active_music_session, as_musician, tracks, audio_latency)

        if connection.errors.any?
          # rollback the transaction to make sure nothing is disturbed in the database
          raise ActiveRecord::Rollback
        end
      end

    end
    if send_track_changed
      Notification.send_tracks_changed(active_music_session)
    end

    unless connection.errors.any?
      user.update_progression_field(:first_music_session_at)
      MusicSessionUserHistory.save(music_session_id, user.id, client_id, tracks)

      if as_musician

        # send to session participants
        Notification.send_session_join(active_music_session, connection, user)
        
        music_session = active_music_session.music_session

        # send "musician joined session" notification only if it's not a band session since there will be a "band joined session" notification
        if music_session.band.nil?
          Notification.send_musician_session_join(music_session, user)
        end
      end
    end

    connection
  end
  
  def participant_delete(user, connection, active_music_session)
    
    if connection.user.id != user.id
      raise JamPermissionError, "you do not own this connection"
    end

    recordingId = nil

    tracks_changed = false
    active_music_session.with_lock do # VRFS-1297
      ConnectionManager.new.leave_music_session(user, connection, active_music_session) do
        active_music_session.tick_track_changes
        tracks_changed = true
        recording =  active_music_session.stop_recording # stop any ongoing recording, if there is one
        recordingId = recording.id unless recording.nil?
      end
    end

    if tracks_changed
      Notification.send_tracks_changed(active_music_session)
    end

    Notification.send_session_depart(active_music_session, connection.client_id, user, recordingId)
  end

  def sync_tracks(active_music_session, client_id, new_tracks, backing_tracks, metronome_open)
    tracks = nil
    active_music_session.with_lock do # VRFS-1297
      tracks = Track.sync(client_id, new_tracks, backing_tracks, metronome_open)
      active_music_session.tick_track_changes
    end
    Notification.send_tracks_changed(active_music_session)
    tracks
  end
end
