// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "chrome/browser/ui/cocoa/custom_frame_view.h"

#import <Carbon/Carbon.h>
#include <crt_externs.h>
#import <objc/runtime.h>
#include <string.h>

#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_nsautorelease_pool.h"

@interface NSView (Swizzles)
- (NSPoint)_fullScreenButtonOriginOriginal;
@end

@interface NSWindow (FramedBrowserWindow)
- (NSPoint)fullScreenButtonOriginAdjustment;
@end

@interface CustomFrameView : NSView

// Clang emits a warning if designated initializers don't call the super
// initializer, even if the method raises an exception.
// http://www.crbug.com/479019.
- (id)initWithFrame:(NSRect)frame UNAVAILABLE_ATTRIBUTE;
- (id)initWithCoder:(NSCoder*)coder UNAVAILABLE_ATTRIBUTE;

@end

@implementation CustomFrameView

+ (void)load {
  // Swizzling should only happen in the browser process. Interacting with
  // AppKit will run +[borderViewClass initialize] in the renderer, which
  // may establish Mach IPC with com.apple.windowserver.
  // Note that CommandLine has not been initialized yet, since this is running
  // as a module initializer.
  const char* const* const argv = *_NSGetArgv();
  const int argc = *_NSGetArgc();
  const char kType[] = "--type=";
  for (int i = 1; i < argc; ++i) {
    const char* arg = argv[i];
    if (strncmp(arg, kType, strlen(kType)) == 0)
      return;
  }

  // In Yosemite, the fullscreen button replaces the zoom button. We no longer
  // need to swizzle out this AppKit private method.
  if (!base::mac::IsOSMavericksOrEarlier())
    return;

  base::mac::ScopedNSAutoreleasePool pool;

  // On 10.8+ the background for textured windows are no longer drawn by
  // NSGrayFrame, and NSThemeFrame is used instead <http://crbug.com/114745>.
  Class borderViewClass = NSClassFromString(
      base::mac::IsOSMountainLionOrLater() ? @"NSThemeFrame" : @"NSGrayFrame");
  DCHECK(borderViewClass);
  if (!borderViewClass) return;

  // Swizzle the method that sets the origin for the Lion fullscreen button.
  // Do nothing if it cannot be found.
  Method m0 = class_getInstanceMethod([self class],
                               @selector(_fullScreenButtonOrigin));
  if (m0) {
    BOOL didAdd = class_addMethod(borderViewClass,
                                  @selector(_fullScreenButtonOriginOriginal),
                                  method_getImplementation(m0),
                                  method_getTypeEncoding(m0));
    if (didAdd) {
      Method m1 = class_getInstanceMethod(borderViewClass,
                                          @selector(_fullScreenButtonOrigin));
      Method m2 = class_getInstanceMethod(
          borderViewClass, @selector(_fullScreenButtonOriginOriginal));
      if (m1 && m2) {
        method_exchangeImplementations(m1, m2);
      }
    }
  }
}

- (id)initWithFrame:(NSRect)frame {
  // This class is not for instantiating.
  [self doesNotRecognizeSelector:_cmd];
  return nil;
}

- (id)initWithCoder:(NSCoder*)coder {
  // This class is not for instantiating.
  [self doesNotRecognizeSelector:_cmd];
  return nil;
}

// Override to move the fullscreen button to the left of the profile avatar.
- (NSPoint)_fullScreenButtonOrigin {
  NSWindow* window = [self window];
  NSPoint offset = NSZeroPoint;

  if ([window respondsToSelector:@selector(fullScreenButtonOriginAdjustment)])
    offset = [window fullScreenButtonOriginAdjustment];

  NSPoint origin = [self _fullScreenButtonOriginOriginal];
  origin.x += offset.x;
  origin.y += offset.y;
  return origin;
}

@end