/*
 * Copyright 2015 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef COBALT_CSSOM_CSS_FONT_FACE_DECLARATION_DATA_H_
#define COBALT_CSSOM_CSS_FONT_FACE_DECLARATION_DATA_H_

#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "cobalt/cssom/css_declaration_data.h"
#include "cobalt/cssom/property_value.h"

namespace cobalt {
namespace cssom {

// CSSFontFaceDeclarationData which has PropertyValue type properties only used
// internally and it is not exposed to JavaScript.
class CSSFontFaceDeclarationData : public CSSDeclarationData {
 public:
  CSSFontFaceDeclarationData();

  // From CSSDeclarationData
  bool IsSupportedPropertyKey(PropertyKey key) const OVERRIDE;
  scoped_refptr<PropertyValue> GetPropertyValue(PropertyKey key) const OVERRIDE;
  void SetPropertyValueAndImportance(
      PropertyKey key, const scoped_refptr<PropertyValue>& property_value,
      bool important) OVERRIDE {
    UNREFERENCED_PARAMETER(important);
    SetPropertyValue(key, property_value);
  }
  void ClearPropertyValueAndImportance(PropertyKey key) OVERRIDE {
    SetPropertyValue(key, NULL);
  }

  // Web API: CSSFontFaceRule
  //
  const scoped_refptr<PropertyValue>& family() const { return family_; }
  void set_family(const scoped_refptr<PropertyValue>& family) {
    family_ = family;
  }

  const scoped_refptr<PropertyValue>& src() const { return src_; }
  void set_src(const scoped_refptr<PropertyValue>& src) { src_ = src; }

  const scoped_refptr<PropertyValue>& style() const { return style_; }
  void set_style(const scoped_refptr<PropertyValue>& style) { style_ = style; }

  const scoped_refptr<PropertyValue>& weight() const { return weight_; }
  void set_weight(const scoped_refptr<PropertyValue>& weight) {
    weight_ = weight;
  }

  const scoped_refptr<PropertyValue>& unicode_range() const {
    return unicode_range_;
  }
  void set_unicode_range(const scoped_refptr<PropertyValue>& unicode_range) {
    unicode_range_ = unicode_range;
  }

  // Rest of public methods.

  void SetPropertyValue(PropertyKey key,
                        const scoped_refptr<PropertyValue>& property_value);

  void AssignFrom(const CSSFontFaceDeclarationData& rhs);

 private:
  scoped_refptr<PropertyValue>* GetPropertyValueReference(PropertyKey key);

  scoped_refptr<PropertyValue> family_;
  scoped_refptr<PropertyValue> src_;
  scoped_refptr<PropertyValue> style_;
  scoped_refptr<PropertyValue> weight_;
  scoped_refptr<PropertyValue> unicode_range_;
};

}  // namespace cssom
}  // namespace cobalt

#endif  // COBALT_CSSOM_CSS_FONT_FACE_DECLARATION_DATA_H_
