/*
 * libjingle
 * Copyright 2013 Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif

#import "RTCPeerConnection+Internal.h"

#import "RTCDataChannel+Internal.h"
#import "RTCEnumConverter.h"
#import "RTCICECandidate+Internal.h"
#import "RTCICEServer+Internal.h"
#import "RTCMediaConstraints+Internal.h"
#import "RTCMediaStream+Internal.h"
#import "RTCMediaStreamTrack+Internal.h"
#import "RTCPeerConnectionObserver.h"
#import "RTCSessionDescription+Internal.h"
#import "RTCSessionDescription.h"
#import "RTCSessionDescriptionDelegate.h"
#import "RTCStatsDelegate.h"
#import "RTCStatsReport+Internal.h"

#include "talk/app/webrtc/jsep.h"

NSString* const kRTCSessionDescriptionDelegateErrorDomain = @"RTCSDPError";
int const kRTCSessionDescriptionDelegateErrorCode = -1;

namespace webrtc {

class RTCCreateSessionDescriptionObserver
    : public CreateSessionDescriptionObserver {
 public:
  RTCCreateSessionDescriptionObserver(
      id<RTCSessionDescriptionDelegate> delegate,
      RTCPeerConnection* peerConnection) {
    _delegate = delegate;
    _peerConnection = peerConnection;
  }

  virtual void OnSuccess(SessionDescriptionInterface* desc) OVERRIDE {
    RTCSessionDescription* session =
        [[RTCSessionDescription alloc] initWithSessionDescription:desc];
    [_delegate peerConnection:_peerConnection
        didCreateSessionDescription:session
                              error:nil];
    delete desc;
  }

  virtual void OnFailure(const std::string& error) OVERRIDE {
    NSString* str = @(error.c_str());
    NSError* err =
        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
                            code:kRTCSessionDescriptionDelegateErrorCode
                        userInfo:@{@"error" : str}];
    [_delegate peerConnection:_peerConnection
        didCreateSessionDescription:nil
                              error:err];
  }

 private:
  id<RTCSessionDescriptionDelegate> _delegate;
  RTCPeerConnection* _peerConnection;
};

class RTCSetSessionDescriptionObserver : public SetSessionDescriptionObserver {
 public:
  RTCSetSessionDescriptionObserver(id<RTCSessionDescriptionDelegate> delegate,
                                   RTCPeerConnection* peerConnection) {
    _delegate = delegate;
    _peerConnection = peerConnection;
  }

  virtual void OnSuccess() OVERRIDE {
    [_delegate peerConnection:_peerConnection
        didSetSessionDescriptionWithError:nil];
  }

  virtual void OnFailure(const std::string& error) OVERRIDE {
    NSString* str = @(error.c_str());
    NSError* err =
        [NSError errorWithDomain:kRTCSessionDescriptionDelegateErrorDomain
                            code:kRTCSessionDescriptionDelegateErrorCode
                        userInfo:@{@"error" : str}];
    [_delegate peerConnection:_peerConnection
        didSetSessionDescriptionWithError:err];
  }

 private:
  id<RTCSessionDescriptionDelegate> _delegate;
  RTCPeerConnection* _peerConnection;
};

class RTCStatsObserver : public StatsObserver {
 public:
  RTCStatsObserver(id<RTCStatsDelegate> delegate,
                   RTCPeerConnection* peerConnection) {
    _delegate = delegate;
    _peerConnection = peerConnection;
  }

  virtual void OnComplete(const StatsReports& reports) OVERRIDE {
    NSMutableArray* stats = [NSMutableArray arrayWithCapacity:reports.size()];
    for (const auto* report : reports) {
      RTCStatsReport* statsReport =
          [[RTCStatsReport alloc] initWithStatsReport:*report];
      [stats addObject:statsReport];
    }
    [_delegate peerConnection:_peerConnection didGetStats:stats];
  }

 private:
  id<RTCStatsDelegate> _delegate;
  RTCPeerConnection* _peerConnection;
};
}

@implementation RTCPeerConnection {
  NSMutableArray* _localStreams;
  rtc::scoped_ptr<webrtc::RTCPeerConnectionObserver> _observer;
  rtc::scoped_refptr<webrtc::PeerConnectionInterface> _peerConnection;
}

- (BOOL)addICECandidate:(RTCICECandidate*)candidate {
  rtc::scoped_ptr<const webrtc::IceCandidateInterface> iceCandidate(
      candidate.candidate);
  return self.peerConnection->AddIceCandidate(iceCandidate.get());
}

- (BOOL)addStream:(RTCMediaStream*)stream {
  BOOL ret = self.peerConnection->AddStream(stream.mediaStream);
  if (!ret) {
    return NO;
  }
  [_localStreams addObject:stream];
  return YES;
}

- (RTCDataChannel*)createDataChannelWithLabel:(NSString*)label
                                       config:(RTCDataChannelInit*)config {
  std::string labelString([label UTF8String]);
  rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
      self.peerConnection->CreateDataChannel(labelString,
                                             config.dataChannelInit);
  return [[RTCDataChannel alloc] initWithDataChannel:dataChannel];
}

- (void)createAnswerWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
                     constraints:(RTCMediaConstraints*)constraints {
  rtc::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
      observer(new rtc::RefCountedObject<
          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
  self.peerConnection->CreateAnswer(observer, constraints.constraints);
}

- (void)createOfferWithDelegate:(id<RTCSessionDescriptionDelegate>)delegate
                    constraints:(RTCMediaConstraints*)constraints {
  rtc::scoped_refptr<webrtc::RTCCreateSessionDescriptionObserver>
      observer(new rtc::RefCountedObject<
          webrtc::RTCCreateSessionDescriptionObserver>(delegate, self));
  self.peerConnection->CreateOffer(observer, constraints.constraints);
}

- (void)removeStream:(RTCMediaStream*)stream {
  self.peerConnection->RemoveStream(stream.mediaStream);
  [_localStreams removeObject:stream];
}

- (void)setLocalDescriptionWithDelegate:
            (id<RTCSessionDescriptionDelegate>)delegate
                     sessionDescription:(RTCSessionDescription*)sdp {
  rtc::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
      new rtc::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
          delegate, self));
  self.peerConnection->SetLocalDescription(observer, sdp.sessionDescription);
}

- (void)setRemoteDescriptionWithDelegate:
            (id<RTCSessionDescriptionDelegate>)delegate
                      sessionDescription:(RTCSessionDescription*)sdp {
  rtc::scoped_refptr<webrtc::RTCSetSessionDescriptionObserver> observer(
      new rtc::RefCountedObject<webrtc::RTCSetSessionDescriptionObserver>(
          delegate, self));
  self.peerConnection->SetRemoteDescription(observer, sdp.sessionDescription);
}

- (BOOL)updateICEServers:(NSArray*)servers
             constraints:(RTCMediaConstraints*)constraints {
  webrtc::PeerConnectionInterface::IceServers iceServers;
  for (RTCICEServer* server in servers) {
    iceServers.push_back(server.iceServer);
  }
  return self.peerConnection->UpdateIce(iceServers, constraints.constraints);
}

- (RTCSessionDescription*)localDescription {
  const webrtc::SessionDescriptionInterface* sdi =
      self.peerConnection->local_description();
  return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
             : nil;
}

- (NSArray*)localStreams {
  return [_localStreams copy];
}

- (RTCSessionDescription*)remoteDescription {
  const webrtc::SessionDescriptionInterface* sdi =
      self.peerConnection->remote_description();
  return sdi ? [[RTCSessionDescription alloc] initWithSessionDescription:sdi]
             : nil;
}

- (RTCICEConnectionState)iceConnectionState {
  return [RTCEnumConverter
      convertIceConnectionStateToObjC:self.peerConnection
                                          ->ice_connection_state()];
}

- (RTCICEGatheringState)iceGatheringState {
  return [RTCEnumConverter
      convertIceGatheringStateToObjC:self.peerConnection
                                         ->ice_gathering_state()];
}

- (RTCSignalingState)signalingState {
  return [RTCEnumConverter
      convertSignalingStateToObjC:self.peerConnection->signaling_state()];
}

- (void)close {
  self.peerConnection->Close();
}

- (BOOL)getStatsWithDelegate:(id<RTCStatsDelegate>)delegate
            mediaStreamTrack:(RTCMediaStreamTrack*)mediaStreamTrack
            statsOutputLevel:(RTCStatsOutputLevel)statsOutputLevel {
  rtc::scoped_refptr<webrtc::RTCStatsObserver> observer(
      new rtc::RefCountedObject<webrtc::RTCStatsObserver>(delegate,
                                                                self));
  webrtc::PeerConnectionInterface::StatsOutputLevel nativeOutputLevel =
      [RTCEnumConverter convertStatsOutputLevelToNative:statsOutputLevel];
  return self.peerConnection->GetStats(
      observer, mediaStreamTrack.mediaTrack, nativeOutputLevel);
}

@end

@implementation RTCPeerConnection (Internal)

- (instancetype)initWithFactory:(webrtc::PeerConnectionFactoryInterface*)factory
     iceServers:(const webrtc::PeerConnectionInterface::IceServers&)iceServers
    constraints:(const webrtc::MediaConstraintsInterface*)constraints {
  NSParameterAssert(factory != NULL);
  if (self = [super init]) {
    _observer.reset(new webrtc::RTCPeerConnectionObserver(self));
    _peerConnection = factory->CreatePeerConnection(
        iceServers, constraints, NULL, NULL, _observer.get());
    _localStreams = [[NSMutableArray alloc] init];
  }
  return self;
}

- (rtc::scoped_refptr<webrtc::PeerConnectionInterface>)peerConnection {
  return _peerConnection;
}

@end
